Commit 33be6271 authored by WANG Cong's avatar WANG Cong Committed by David S. Miller

net_sched: act: use standard struct list_head

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 <jhs@mojatatu.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: default avatarCong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d84231d3
...@@ -60,7 +60,7 @@ struct tc_action { ...@@ -60,7 +60,7 @@ struct tc_action {
const struct tc_action_ops *ops; const struct tc_action_ops *ops;
__u32 type; /* for backward compat(TCA_OLD_COMPAT) */ __u32 type; /* for backward compat(TCA_OLD_COMPAT) */
__u32 order; __u32 order;
struct tc_action *next; struct list_head list;
}; };
#define TCA_CAP_NONE 0 #define TCA_CAP_NONE 0
...@@ -99,16 +99,16 @@ void tcf_hash_insert(struct tcf_common *p, struct tcf_hashinfo *hinfo); ...@@ -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_register_action(struct tc_action_ops *a);
int tcf_unregister_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); void tcf_action_destroy(struct list_head *actions, int bind);
int tcf_action_exec(struct sk_buff *skb, const struct tc_action *a, int tcf_action_exec(struct sk_buff *skb, const struct list_head *actions,
struct tcf_result *res); 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, 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 tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
struct nlattr *est, char *n, int ovr, struct nlattr *est, char *n, int ovr,
int bind); 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_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_dump_1(struct sk_buff *skb, struct tc_action *a, int, int);
int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int); int tcf_action_copy_stats(struct sk_buff *, struct tc_action *, int);
......
...@@ -62,7 +62,8 @@ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r) ...@@ -62,7 +62,8 @@ tcf_unbind_filter(struct tcf_proto *tp, struct tcf_result *r)
struct tcf_exts { struct tcf_exts {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
struct tc_action *action; __u32 type; /* for backward compat(TCA_OLD_COMPAT) */
struct list_head actions;
#endif #endif
}; };
...@@ -74,6 +75,13 @@ struct tcf_ext_map { ...@@ -74,6 +75,13 @@ struct tcf_ext_map {
int police; 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 * tcf_exts_is_predicative - check if a predicative extension is present
* @exts: tc filter extensions handle * @exts: tc filter extensions handle
...@@ -85,7 +93,7 @@ static inline int ...@@ -85,7 +93,7 @@ static inline int
tcf_exts_is_predicative(struct tcf_exts *exts) tcf_exts_is_predicative(struct tcf_exts *exts)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
return !!exts->action; return !list_empty(&exts->actions);
#else #else
return 0; return 0;
#endif #endif
...@@ -120,8 +128,8 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts, ...@@ -120,8 +128,8 @@ tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
struct tcf_result *res) struct tcf_result *res)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
if (exts->action) if (!list_empty(&exts->actions))
return tcf_action_exec(skb, exts->action, res); return tcf_action_exec(skb, &exts->actions, res);
#endif #endif
return 0; return 0;
} }
......
...@@ -379,7 +379,7 @@ static struct tc_action_ops *tc_lookup_action_id(u32 type) ...@@ -379,7 +379,7 @@ static struct tc_action_ops *tc_lookup_action_id(u32 type)
} }
#endif #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) struct tcf_result *res)
{ {
const struct tc_action *a; const struct tc_action *a;
...@@ -390,7 +390,7 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act, ...@@ -390,7 +390,7 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
ret = TC_ACT_OK; ret = TC_ACT_OK;
goto exec_done; goto exec_done;
} }
while ((a = act) != NULL) { list_for_each_entry(a, actions, list) {
repeat: repeat:
if (a->ops) { if (a->ops) {
ret = a->ops->act(skb, a, res); ret = a->ops->act(skb, a, res);
...@@ -404,27 +404,26 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act, ...@@ -404,27 +404,26 @@ int tcf_action_exec(struct sk_buff *skb, const struct tc_action *act,
if (ret != TC_ACT_PIPE) if (ret != TC_ACT_PIPE)
goto exec_done; goto exec_done;
} }
act = a->next;
} }
exec_done: exec_done:
return ret; return ret;
} }
EXPORT_SYMBOL(tcf_action_exec); 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) {
if (a->ops->cleanup(a, bind) == ACT_P_DELETED) if (a->ops->cleanup(a, bind) == ACT_P_DELETED)
module_put(a->ops->owner); module_put(a->ops->owner);
act = act->next; list_del(&a->list);
kfree(a); kfree(a);
} else { } else {
/*FIXME: Remove later - catch insertion bugs*/ /*FIXME: Remove later - catch insertion bugs*/
WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n"); WARN(1, "tcf_action_destroy: BUG? destroying NULL ops\n");
act = act->next; list_del(&a->list);
kfree(a); kfree(a);
} }
} }
...@@ -470,14 +469,13 @@ tcf_action_dump_1(struct sk_buff *skb, struct tc_action *a, int bind, int ref) ...@@ -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); EXPORT_SYMBOL(tcf_action_dump_1);
int 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; struct tc_action *a;
int err = -EINVAL; int err = -EINVAL;
struct nlattr *nest; struct nlattr *nest;
while ((a = act) != NULL) { list_for_each_entry(a, actions, list) {
act = a->next;
nest = nla_nest_start(skb, a->order); nest = nla_nest_start(skb, a->order);
if (nest == NULL) if (nest == NULL)
goto nla_put_failure; goto nla_put_failure;
...@@ -552,6 +550,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla, ...@@ -552,6 +550,7 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
if (a == NULL) if (a == NULL)
goto err_mod; goto err_mod;
INIT_LIST_HEAD(&a->list);
/* backward compatibility for policer */ /* backward compatibility for policer */
if (name == NULL) if (name == NULL)
err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind); err = a_o->init(net, tb[TCA_ACT_OPTIONS], est, a, ovr, bind);
...@@ -578,37 +577,33 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla, ...@@ -578,37 +577,33 @@ struct tc_action *tcf_action_init_1(struct net *net, struct nlattr *nla,
return ERR_PTR(err); 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, struct nlattr *est, char *name, int ovr,
int bind) int bind, struct list_head *actions)
{ {
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; struct nlattr *tb[TCA_ACT_MAX_PRIO + 1];
struct tc_action *head = NULL, *act, *act_prev = NULL; struct tc_action *act;
int err; int err;
int i; int i;
err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL); err = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
if (err < 0) if (err < 0)
return ERR_PTR(err); return err;
for (i = 1; i <= TCA_ACT_MAX_PRIO && tb[i]; i++) { 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, tb[i], est, name, ovr, bind);
if (IS_ERR(act)) if (IS_ERR(act)) {
err = PTR_ERR(act);
goto err; goto err;
}
act->order = i; act->order = i;
list_add_tail(&act->list, actions);
if (head == NULL)
head = act;
else
act_prev->next = act;
act_prev = act;
} }
return head; return 0;
err: err:
if (head != NULL) tcf_action_destroy(actions, bind);
tcf_action_destroy(head, bind); return err;
return act;
} }
int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
...@@ -653,7 +648,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, ...@@ -653,7 +648,7 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a,
} }
static int 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) u16 flags, int event, int bind, int ref)
{ {
struct tcamsg *t; struct tcamsg *t;
...@@ -673,7 +668,7 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq, ...@@ -673,7 +668,7 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
if (nest == NULL) if (nest == NULL)
goto out_nlmsg_trim; 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; goto out_nlmsg_trim;
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
...@@ -688,14 +683,14 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq, ...@@ -688,14 +683,14 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 portid, u32 seq,
static int static int
act_get_notify(struct net *net, u32 portid, struct nlmsghdr *n, 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; struct sk_buff *skb;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb) if (!skb)
return -ENOBUFS; 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); kfree_skb(skb);
return -EINVAL; return -EINVAL;
} }
...@@ -726,6 +721,7 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid) ...@@ -726,6 +721,7 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
if (a == NULL) if (a == NULL)
goto err_out; goto err_out;
INIT_LIST_HEAD(&a->list);
err = -EINVAL; err = -EINVAL;
a->ops = tc_lookup_action(tb[TCA_ACT_KIND]); a->ops = tc_lookup_action(tb[TCA_ACT_KIND]);
if (a->ops == NULL) if (a->ops == NULL)
...@@ -745,12 +741,12 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid) ...@@ -745,12 +741,12 @@ tcf_action_get_1(struct nlattr *nla, struct nlmsghdr *n, u32 portid)
return ERR_PTR(err); 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) { list_for_each_entry_safe(a, tmp, actions, list) {
act = a->next; list_del(&a->list);
kfree(a); kfree(a);
} }
} }
...@@ -765,6 +761,7 @@ static struct tc_action *create_a(int i) ...@@ -765,6 +761,7 @@ static struct tc_action *create_a(int i)
return NULL; return NULL;
} }
act->order = i; act->order = i;
INIT_LIST_HEAD(&act->list);
return act; return act;
} }
...@@ -852,7 +849,8 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -852,7 +849,8 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
{ {
int i, ret; int i, ret;
struct nlattr *tb[TCA_ACT_MAX_PRIO + 1]; 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); ret = nla_parse_nested(tb, TCA_ACT_MAX_PRIO, nla, NULL);
if (ret < 0) if (ret < 0)
...@@ -872,16 +870,11 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -872,16 +870,11 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
goto err; goto err;
} }
act->order = i; act->order = i;
list_add_tail(&act->list, &actions);
if (head == NULL)
head = act;
else
act_prev->next = act;
act_prev = act;
} }
if (event == RTM_GETACTION) if (event == RTM_GETACTION)
ret = act_get_notify(net, portid, n, head, event); ret = act_get_notify(net, portid, n, &actions, event);
else { /* delete */ else { /* delete */
struct sk_buff *skb; struct sk_buff *skb;
...@@ -891,7 +884,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -891,7 +884,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
goto err; 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) { 0, 1) <= 0) {
kfree_skb(skb); kfree_skb(skb);
ret = -EINVAL; ret = -EINVAL;
...@@ -899,7 +892,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -899,7 +892,7 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
} }
/* now do the delete */ /* now do the delete */
tcf_action_destroy(head, 0); tcf_action_destroy(&actions, 0);
ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC, ret = rtnetlink_send(skb, net, portid, RTNLGRP_TC,
n->nlmsg_flags & NLM_F_ECHO); n->nlmsg_flags & NLM_F_ECHO);
if (ret > 0) if (ret > 0)
...@@ -907,11 +900,11 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -907,11 +900,11 @@ tca_action_gd(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
return ret; return ret;
} }
err: err:
cleanup_a(head); cleanup_a(&actions);
return ret; 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) u32 portid, u32 seq, int event, u16 flags)
{ {
struct tcamsg *t; struct tcamsg *t;
...@@ -939,7 +932,7 @@ static int tcf_add_notify(struct net *net, struct tc_action *a, ...@@ -939,7 +932,7 @@ static int tcf_add_notify(struct net *net, struct tc_action *a,
if (nest == NULL) if (nest == NULL)
goto out_kfree_skb; 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; goto out_kfree_skb;
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
...@@ -963,26 +956,18 @@ tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n, ...@@ -963,26 +956,18 @@ tcf_action_add(struct net *net, struct nlattr *nla, struct nlmsghdr *n,
u32 portid, int ovr) u32 portid, int ovr)
{ {
int ret = 0; int ret = 0;
struct tc_action *act; LIST_HEAD(actions);
struct tc_action *a;
u32 seq = n->nlmsg_seq; u32 seq = n->nlmsg_seq;
act = tcf_action_init(net, nla, NULL, NULL, ovr, 0); ret = tcf_action_init(net, nla, NULL, NULL, ovr, 0, &actions);
if (act == NULL) if (ret)
goto done; goto done;
if (IS_ERR(act)) {
ret = PTR_ERR(act);
goto done;
}
/* dump then free all the actions after update; inserted policy /* dump then free all the actions after update; inserted policy
* stays intact * stays intact
*/ */
ret = tcf_add_notify(net, act, portid, seq, RTM_NEWACTION, n->nlmsg_flags); ret = tcf_add_notify(net, &actions, portid, seq, RTM_NEWACTION, n->nlmsg_flags);
for (a = act; a; a = act) { cleanup_a(&actions);
act = a->next;
kfree(a);
}
done: done:
return ret; return ret;
} }
......
...@@ -500,10 +500,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -500,10 +500,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts) void tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
if (exts->action) { tcf_action_destroy(&exts->actions, TCA_ACT_UNBIND);
tcf_action_destroy(exts->action, TCA_ACT_UNBIND); INIT_LIST_HEAD(&exts->actions);
exts->action = NULL;
}
#endif #endif
} }
EXPORT_SYMBOL(tcf_exts_destroy); EXPORT_SYMBOL(tcf_exts_destroy);
...@@ -518,6 +516,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, ...@@ -518,6 +516,7 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
{ {
struct tc_action *act; struct tc_action *act;
INIT_LIST_HEAD(&exts->actions);
if (map->police && tb[map->police]) { if (map->police && tb[map->police]) {
act = tcf_action_init_1(net, tb[map->police], rate_tlv, act = tcf_action_init_1(net, tb[map->police], rate_tlv,
"police", TCA_ACT_NOREPLACE, "police", TCA_ACT_NOREPLACE,
...@@ -525,16 +524,15 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb, ...@@ -525,16 +524,15 @@ int tcf_exts_validate(struct net *net, struct tcf_proto *tp, struct nlattr **tb,
if (IS_ERR(act)) if (IS_ERR(act))
return PTR_ERR(act); return PTR_ERR(act);
act->type = TCA_OLD_COMPAT; act->type = exts->type = TCA_OLD_COMPAT;
exts->action = act; list_add(&act->list, &exts->actions);
} else if (map->action && tb[map->action]) { } else if (map->action && tb[map->action]) {
act = tcf_action_init(net, tb[map->action], rate_tlv, int err;
err = tcf_action_init(net, tb[map->action], rate_tlv,
NULL, TCA_ACT_NOREPLACE, NULL, TCA_ACT_NOREPLACE,
TCA_ACT_BIND); TCA_ACT_BIND, &exts->actions);
if (IS_ERR(act)) if (err)
return PTR_ERR(act); return err;
exts->action = act;
} }
} }
#else #else
...@@ -551,43 +549,45 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, ...@@ -551,43 +549,45 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
struct tcf_exts *src) struct tcf_exts *src)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
if (src->action) { if (!list_empty(&src->actions)) {
struct tc_action *act; LIST_HEAD(tmp);
tcf_tree_lock(tp); tcf_tree_lock(tp);
act = dst->action; list_splice_init(&dst->actions, &tmp);
dst->action = src->action; list_splice(&src->actions, &dst->actions);
tcf_tree_unlock(tp); tcf_tree_unlock(tp);
if (act) tcf_action_destroy(&tmp, TCA_ACT_UNBIND);
tcf_action_destroy(act, TCA_ACT_UNBIND);
} }
#endif #endif
} }
EXPORT_SYMBOL(tcf_exts_change); EXPORT_SYMBOL(tcf_exts_change);
#define tcf_exts_first_act(ext) \
list_first_entry(&(exts)->actions, struct tc_action, list)
int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts, int tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
const struct tcf_ext_map *map) const struct tcf_ext_map *map)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
if (map->action && exts->action) { if (map->action && !list_empty(&exts->actions)) {
/* /*
* again for backward compatible mode - we want * again for backward compatible mode - we want
* to work with both old and new modes of entering * to work with both old and new modes of entering
* tc data even if iproute2 was newer - jhs * tc data even if iproute2 was newer - jhs
*/ */
struct nlattr *nest; struct nlattr *nest;
if (exts->type != TCA_OLD_COMPAT) {
if (exts->action->type != TCA_OLD_COMPAT) {
nest = nla_nest_start(skb, map->action); nest = nla_nest_start(skb, map->action);
if (nest == NULL) if (nest == NULL)
goto nla_put_failure; goto nla_put_failure;
if (tcf_action_dump(skb, exts->action, 0, 0) < 0) if (tcf_action_dump(skb, &exts->actions, 0, 0) < 0)
goto nla_put_failure; goto nla_put_failure;
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
} else if (map->police) { } else if (map->police) {
struct tc_action *act = tcf_exts_first_act(exts);
nest = nla_nest_start(skb, map->police); nest = nla_nest_start(skb, map->police);
if (nest == NULL) if (nest == NULL)
goto nla_put_failure; goto nla_put_failure;
if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0) if (tcf_action_dump_old(skb, act, 0, 0) < 0)
goto nla_put_failure; goto nla_put_failure;
nla_nest_end(skb, nest); nla_nest_end(skb, nest);
} }
...@@ -604,13 +604,11 @@ int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts, ...@@ -604,13 +604,11 @@ int tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
const struct tcf_ext_map *map) const struct tcf_ext_map *map)
{ {
#ifdef CONFIG_NET_CLS_ACT #ifdef CONFIG_NET_CLS_ACT
if (exts->action) struct tc_action *a = tcf_exts_first_act(exts);
if (tcf_action_copy_stats(skb, exts->action, 1) < 0) if (tcf_action_copy_stats(skb, a, 1) < 0)
goto nla_put_failure; return -1;
#endif #endif
return 0; return 0;
nla_put_failure: __attribute__ ((unused))
return -1;
} }
EXPORT_SYMBOL(tcf_exts_dump_stats); EXPORT_SYMBOL(tcf_exts_dump_stats);
......
...@@ -191,6 +191,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb, ...@@ -191,6 +191,7 @@ static int basic_change(struct net *net, struct sk_buff *in_skb,
if (f == NULL) if (f == NULL)
goto errout; goto errout;
tcf_exts_init(&f->exts);
err = -EINVAL; err = -EINVAL;
if (handle) if (handle)
f->handle = handle; f->handle = handle;
......
...@@ -271,6 +271,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, ...@@ -271,6 +271,7 @@ static int cls_bpf_change(struct net *net, struct sk_buff *in_skb,
if (prog == NULL) if (prog == NULL)
return -ENOBUFS; return -ENOBUFS;
tcf_exts_init(&prog->exts);
if (handle == 0) if (handle == 0)
prog->handle = cls_bpf_grab_new_handle(tp, head); prog->handle = cls_bpf_grab_new_handle(tp, head);
else else
......
...@@ -203,6 +203,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb, ...@@ -203,6 +203,7 @@ static int cls_cgroup_change(struct net *net, struct sk_buff *in_skb,
if (head == NULL) if (head == NULL)
return -ENOBUFS; return -ENOBUFS;
tcf_exts_init(&head->exts);
head->handle = handle; head->handle = handle;
tcf_tree_lock(tp); tcf_tree_lock(tp);
......
...@@ -455,6 +455,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb, ...@@ -455,6 +455,7 @@ static int flow_change(struct net *net, struct sk_buff *in_skb,
f->handle = handle; f->handle = handle;
f->mask = ~0U; f->mask = ~0U;
tcf_exts_init(&f->exts);
get_random_bytes(&f->hashrnd, 4); get_random_bytes(&f->hashrnd, 4);
f->perturb_timer.function = flow_perturbation; f->perturb_timer.function = flow_perturbation;
......
...@@ -280,6 +280,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb, ...@@ -280,6 +280,7 @@ static int fw_change(struct net *net, struct sk_buff *in_skb,
if (f == NULL) if (f == NULL)
return -ENOBUFS; return -ENOBUFS;
tcf_exts_init(&f->exts);
f->id = handle; f->id = handle;
err = fw_change_attrs(net, tp, f, tb, tca, base); err = fw_change_attrs(net, tp, f, tb, tca, base);
......
...@@ -481,6 +481,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb, ...@@ -481,6 +481,7 @@ static int route4_change(struct net *net, struct sk_buff *in_skb,
if (f == NULL) if (f == NULL)
goto errout; goto errout;
tcf_exts_init(&f->exts);
err = route4_set_parms(net, tp, base, f, handle, head, tb, err = route4_set_parms(net, tp, base, f, handle, head, tb,
tca[TCA_RATE], 1); tca[TCA_RATE], 1);
if (err < 0) if (err < 0)
......
...@@ -471,6 +471,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb, ...@@ -471,6 +471,7 @@ static int rsvp_change(struct net *net, struct sk_buff *in_skb,
if (f == NULL) if (f == NULL)
goto errout2; goto errout2;
tcf_exts_init(&f->exts);
h2 = 16; h2 = 16;
if (tb[TCA_RSVP_SRC]) { if (tb[TCA_RSVP_SRC]) {
memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src)); memcpy(f->src, nla_data(tb[TCA_RSVP_SRC]), sizeof(f->src));
......
...@@ -215,11 +215,14 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base, ...@@ -215,11 +215,14 @@ tcindex_set_parms(struct net *net, struct tcf_proto *tp, unsigned long base,
memcpy(&cp, p, sizeof(cp)); memcpy(&cp, p, sizeof(cp));
memset(&new_filter_result, 0, sizeof(new_filter_result)); memset(&new_filter_result, 0, sizeof(new_filter_result));
tcf_exts_init(&new_filter_result.exts);
if (old_r) if (old_r)
memcpy(&cr, r, sizeof(cr)); memcpy(&cr, r, sizeof(cr));
else else {
memset(&cr, 0, sizeof(cr)); memset(&cr, 0, sizeof(cr));
tcf_exts_init(&cr.exts);
}
if (tb[TCA_TCINDEX_HASH]) if (tb[TCA_TCINDEX_HASH])
cp.hash = nla_get_u32(tb[TCA_TCINDEX_HASH]); cp.hash = nla_get_u32(tb[TCA_TCINDEX_HASH]);
......
...@@ -646,6 +646,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, ...@@ -646,6 +646,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
n->ht_up = ht; n->ht_up = ht;
n->handle = handle; n->handle = handle;
n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0; n->fshift = s->hmask ? ffs(ntohl(s->hmask)) - 1 : 0;
tcf_exts_init(&n->exts);
#ifdef CONFIG_CLS_U32_MARK #ifdef CONFIG_CLS_U32_MARK
if (tb[TCA_U32_MARK]) { if (tb[TCA_U32_MARK]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment