Skip to content

Commit

Permalink
net_sched: act: use standard struct list_head
Browse files Browse the repository at this point in the history
Currently actions are chained by a singly linked list,
therefore it is a bit hard to add and remove a specific
entry. Convert it to struct list_head so that in the
latter patch we can remove an action without finding
its head.

Cc: Jamal Hadi Salim <[email protected]>
Cc: David S. Miller <[email protected]>
Signed-off-by: Cong Wang <[email protected]>
Signed-off-by: Jamal Hadi Salim <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
congwang authored and davem330 committed Dec 18, 2013
1 parent d84231d commit 33be627
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 99 deletions.
12 changes: 6 additions & 6 deletions include/net/act_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ struct tc_action {
const struct tc_action_ops *ops;
__u32 type; /* for backward compat(TCA_OLD_COMPAT) */
__u32 order;
struct tc_action *next;
struct list_head list;
};

#define TCA_CAP_NONE 0
Expand Down Expand Up @@ -99,16 +99,16 @@ void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo);

int tcf_register_action(struct tc_action_ops *a);
int tcf_unregister_action(struct tc_action_ops *a);
void tcf_action_destroy(struct tc_action *a, int bind);
int tcf_action_exec(struct sk_buff *skb, const struct tc_action *a,
void tcf_action_destroy(struct list_head *actions, int bind);
int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
struct tcf_result *res);
struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
int tcf_action_init(struct net *net, struct nlattr *nla,
struct nlattr *est, char *n, int ovr,
int bind);
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_dump(struct sk_buff *skb, struct tc_action *a, int, int);
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);
int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
Expand Down
16 changes: 12 additions & 4 deletions include/net/pkt_cls.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)

struct tcf_exts {
#ifdef CONFIG_NET_CLS_ACT
struct tc_action *action;
__u32 type; /* for backward compat(TCA_OLD_COMPAT) */
struct list_head actions;
#endif
};

Expand All @@ -74,6 +75,13 @@ struct tcf_ext_map {
int police;
};

static inline void tcf_exts_init(struct tcf_exts *exts)
{
#ifdef CONFIG_NET_CLS_ACT
INIT_LIST_HEAD(&exts->actions);
#endif
}

/**
* tcf_exts_is_predicative - check if a predicative extension is present
* @exts: tc filter extensions handle
Expand All @@ -85,7 +93,7 @@ static inline int
tcf_exts_is_predicative(struct tcf_exts *exts)
{
#ifdef CONFIG_NET_CLS_ACT
return !!exts->action;
return !list_empty(&exts->actions);
#else
return 0;
#endif
Expand Down Expand Up @@ -120,8 +128,8 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
struct tcf_result *res)
{
#ifdef CONFIG_NET_CLS_ACT
if (exts->action)
return tcf_action_exec(skb, exts->action, res);
if (!list_empty(&exts->actions))
return tcf_action_exec(skb, &exts->actions, res);
#endif
return 0;
}
Expand Down
105 changes: 45 additions & 60 deletions net/sched/act_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ static struct tc_action_ops *tc_lookup_action_id(u32 type)
}
#endif

int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
struct tcf_result *res)
{
const struct tc_action *a;
Expand All @@ -390,7 +390,7 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
ret = TC_ACT_OK;
goto exec_done;
}
while ((a = act) != NULL) {
list_for_each_entry(a, actions, list) {
repeat:
if (a->ops) {
ret = a->ops->act(skb, a, res);
Expand All @@ -404,27 +404,26 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
if (ret != TC_ACT_PIPE)
goto exec_done;
}
act = a->next;
}
exec_done:
return ret;
}
EXPORT_SYMBOL(tcf_action_exec);

void tcf_action_destroy(struct tc_action *act, int bind)
void tcf_action_destroy(struct list_head *actions, int bind)
{
struct tc_action *a;
struct tc_action *a, *tmp;

for (a = act; a; a = act) {
list_for_each_entry_safe(a, tmp, actions, list) {
if (a->ops) {
if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
module_put(a->ops->owner);
act = act->next;
list_del(&a->list);
kfree(a);
} else {
/*FIXME: Remove later - catch insertion bugs*/
WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
act = act->next;
list_del(&a->list);
kfree(a);
}
}
Expand Down Expand Up @@ -470,14 +469,13 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref)
EXPORT_SYMBOL(tcf_action_dump_1);

int
tcf_action_dump(struct sk_buff *skb, struct tc_action *act, int bind, int ref)
tcf_action_dump(struct sk_buff *skb, struct list_head *actions, int bind, int ref)
{
struct tc_action *a;
int err = -EINVAL;
struct nlattr *nest;

while ((a = act) != NULL) {
act = a->next;
list_for_each_entry(a, actions, list) {
nest = nla_nest_start(skb, a->order);
if (nest == NULL)
goto nla_put_failure;
Expand Down Expand Up @@ -552,6 +550,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
if (a == NULL)
goto err_mod;

INIT_LIST_HEAD(&a->list);
/* backward compatibility for policer */
if (name == NULL)
err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
Expand All @@ -578,37 +577,33 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
return ERR_PTR(err);
}

struct tc_action *tcf_action_init(struct net *net, struct nlattr *nla,
int tcf_action_init(struct net *net, struct nlattr *nla,
struct nlattr *est, char *name, int ovr,
int bind)
int bind, struct list_head *actions)
{
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
struct tc_action *head = NULL, *act, *act_prev = NULL;
struct tc_action *act;
int err;
int i;

err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
if (err < 0)
return ERR_PTR(err);
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);
if (IS_ERR(act))
if (IS_ERR(act)) {
err = PTR_ERR(act);
goto err;
}
act->order = i;

if (head == NULL)
head = act;
else
act_prev->next = act;
act_prev = act;
list_add_tail(&act->list, actions);
}
return head;
return 0;

err:
if (head != NULL)
tcf_action_destroy(head, bind);
return act;
tcf_action_destroy(actions, bind);
return err;
}

int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
Expand Down Expand Up @@ -653,7 +648,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
}

static int
tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
tca_get_fill(struct sk_buff *skb, struct list_head *actions, u32 portid, u32 seq,
u16 flags, int event, int bind, int ref)
{
struct tcamsg *t;
Expand All @@ -673,7 +668,7 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
if (nest == NULL)
goto out_nlmsg_trim;

if (tcf_action_dump(skb, a, bind, ref) < 0)
if (tcf_action_dump(skb, actions, bind, ref) < 0)
goto out_nlmsg_trim;

nla_nest_end(skb, nest);
Expand All @@ -688,14 +683,14 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,

static int
act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n,
struct tc_action *a, int event)
struct list_head *actions, int event)
{
struct sk_buff *skb;

skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb)
return -ENOBUFS;
if (tca_get_fill(skb, a, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
if (tca_get_fill(skb, actions, portid, n->nlmsg_seq, 0, event, 0, 0) <= 0) {
kfree_skb(skb);
return -EINVAL;
}
Expand Down Expand Up @@ -726,6 +721,7 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
if (a == NULL)
goto err_out;

INIT_LIST_HEAD(&a->list);
err = -EINVAL;
a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
if (a->ops == NULL)
Expand All @@ -745,12 +741,12 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
return ERR_PTR(err);
}

static void cleanup_a(struct tc_action *act)
static void cleanup_a(struct list_head *actions)
{
struct tc_action *a;
struct tc_action *a, *tmp;

for (a = act; a; a = act) {
act = a->next;
list_for_each_entry_safe(a, tmp, actions, list) {
list_del(&a->list);
kfree(a);
}
}
Expand All @@ -765,6 +761,7 @@ static struct tc_action *create_a(int i)
return NULL;
}
act->order = i;
INIT_LIST_HEAD(&act->list);
return act;
}

Expand Down Expand Up @@ -852,7 +849,8 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
{
int i, ret;
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
struct tc_action *head = NULL, *act, *act_prev = NULL;
struct tc_action *act;
LIST_HEAD(actions);

ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
if (ret < 0)
Expand All @@ -872,16 +870,11 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
goto err;
}
act->order = i;

if (head == NULL)
head = act;
else
act_prev->next = act;
act_prev = act;
list_add_tail(&act->list, &actions);
}

if (event == RTM_GETACTION)
ret = act_get_notify(net, portid, n, head, event);
ret = act_get_notify(net, portid, n, &actions, event);
else { /* delete */
struct sk_buff *skb;

Expand All @@ -891,27 +884,27 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
goto err;
}

if (tca_get_fill(skb, head, portid, n->nlmsg_seq, 0, event,
if (tca_get_fill(skb, &actions, portid, n->nlmsg_seq, 0, event,
0, 1) <= 0) {
kfree_skb(skb);
ret = -EINVAL;
goto err;
}

/* now do the delete */
tcf_action_destroy(head, 0);
tcf_action_destroy(&actions, 0);
ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
n->nlmsg_flags & NLM_F_ECHO);
if (ret > 0)
return 0;
return ret;
}
err:
cleanup_a(head);
cleanup_a(&actions);
return ret;
}

static int tcf_add_notify(struct net *net, struct tc_action *a,
static int tcf_add_notify(struct net *net, struct list_head *actions,
u32 portid, u32 seq, int event, u16 flags)
{
struct tcamsg *t;
Expand Down Expand Up @@ -939,7 +932,7 @@ static int tcf_add_notify(struct net *net, struct tc_action *a,
if (nest == NULL)
goto out_kfree_skb;

if (tcf_action_dump(skb, a, 0, 0) < 0)
if (tcf_action_dump(skb, actions, 0, 0) < 0)
goto out_kfree_skb;

nla_nest_end(skb, nest);
Expand All @@ -963,26 +956,18 @@ tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
u32 portid, int ovr)
{
int ret = 0;
struct tc_action *act;
struct tc_action *a;
LIST_HEAD(actions);
u32 seq = n->nlmsg_seq;

act = tcf_action_init(net, nla, NULL, NULL, ovr, 0);
if (act == NULL)
goto done;
if (IS_ERR(act)) {
ret = PTR_ERR(act);
ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
if (ret)
goto done;
}

/* dump then free all the actions after update; inserted policy
* stays intact
*/
ret = tcf_add_notify(net, act, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
for (a = act; a; a = act) {
act = a->next;
kfree(a);
}
ret = tcf_add_notify(net, &actions, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
cleanup_a(&actions);
done:
return ret;
}
Expand Down
Loading

0 comments on commit 33be627

Please sign in to comment.