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: Cong Wang <xiyou.wangcong@gmail.com> Signed-off-by: Jamal Hadi Salim <jhs@mojatatu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
d84231d3a2
Коммит
33be627159
|
@ -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);
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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 {
|
||||||
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
|
||||||
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,
|
||||||
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)
|
||||||
}
|
}
|
||||||
#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,
|
||||||
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 @@ repeat:
|
||||||
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 @@ nla_put_failure:
|
||||||
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,
|
||||||
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 @@ err_out:
|
||||||
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 @@ errout:
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
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 @@ out_nlmsg_trim:
|
||||||
|
|
||||||
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)
|
||||||
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 @@ err_out:
|
||||||
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)
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
||||||
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,
|
||||||
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,
|
||||||
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 @@ out:
|
||||||
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,
|
||||||
{
|
{
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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]) {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче