aboutsummaryrefslogtreecommitdiffstats
path: root/net/sched/act_skbmod.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sched/act_skbmod.c')
-rw-r--r--net/sched/act_skbmod.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index 7bac1d78e7a3..1d4c324d0a42 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -16,6 +16,7 @@
16#include <linux/rtnetlink.h> 16#include <linux/rtnetlink.h>
17#include <net/netlink.h> 17#include <net/netlink.h>
18#include <net/pkt_sched.h> 18#include <net/pkt_sched.h>
19#include <net/pkt_cls.h>
19 20
20#include <linux/tc_act/tc_skbmod.h> 21#include <linux/tc_act/tc_skbmod.h>
21#include <net/tc_act/tc_skbmod.h> 22#include <net/tc_act/tc_skbmod.h>
@@ -82,11 +83,13 @@ static const struct nla_policy skbmod_policy[TCA_SKBMOD_MAX + 1] = {
82static int tcf_skbmod_init(struct net *net, struct nlattr *nla, 83static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
83 struct nlattr *est, struct tc_action **a, 84 struct nlattr *est, struct tc_action **a,
84 int ovr, int bind, bool rtnl_held, 85 int ovr, int bind, bool rtnl_held,
86 struct tcf_proto *tp,
85 struct netlink_ext_ack *extack) 87 struct netlink_ext_ack *extack)
86{ 88{
87 struct tc_action_net *tn = net_generic(net, skbmod_net_id); 89 struct tc_action_net *tn = net_generic(net, skbmod_net_id);
88 struct nlattr *tb[TCA_SKBMOD_MAX + 1]; 90 struct nlattr *tb[TCA_SKBMOD_MAX + 1];
89 struct tcf_skbmod_params *p, *p_old; 91 struct tcf_skbmod_params *p, *p_old;
92 struct tcf_chain *goto_ch = NULL;
90 struct tc_skbmod *parm; 93 struct tc_skbmod *parm;
91 struct tcf_skbmod *d; 94 struct tcf_skbmod *d;
92 bool exists = false; 95 bool exists = false;
@@ -153,21 +156,24 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
153 tcf_idr_release(*a, bind); 156 tcf_idr_release(*a, bind);
154 return -EEXIST; 157 return -EEXIST;
155 } 158 }
159 err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
160 if (err < 0)
161 goto release_idr;
156 162
157 d = to_skbmod(*a); 163 d = to_skbmod(*a);
158 164
159 p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL); 165 p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL);
160 if (unlikely(!p)) { 166 if (unlikely(!p)) {
161 tcf_idr_release(*a, bind); 167 err = -ENOMEM;
162 return -ENOMEM; 168 goto put_chain;
163 } 169 }
164 170
165 p->flags = lflags; 171 p->flags = lflags;
166 d->tcf_action = parm->action;
167 172
168 if (ovr) 173 if (ovr)
169 spin_lock_bh(&d->tcf_lock); 174 spin_lock_bh(&d->tcf_lock);
170 /* Protected by tcf_lock if overwriting existing action. */ 175 /* Protected by tcf_lock if overwriting existing action. */
176 goto_ch = tcf_action_set_ctrlact(*a, parm->action, goto_ch);
171 p_old = rcu_dereference_protected(d->skbmod_p, 1); 177 p_old = rcu_dereference_protected(d->skbmod_p, 1);
172 178
173 if (lflags & SKBMOD_F_DMAC) 179 if (lflags & SKBMOD_F_DMAC)
@@ -183,10 +189,18 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
183 189
184 if (p_old) 190 if (p_old)
185 kfree_rcu(p_old, rcu); 191 kfree_rcu(p_old, rcu);
192 if (goto_ch)
193 tcf_chain_put_by_act(goto_ch);
186 194
187 if (ret == ACT_P_CREATED) 195 if (ret == ACT_P_CREATED)
188 tcf_idr_insert(tn, *a); 196 tcf_idr_insert(tn, *a);
189 return ret; 197 return ret;
198put_chain:
199 if (goto_ch)
200 tcf_chain_put_by_act(goto_ch);
201release_idr:
202 tcf_idr_release(*a, bind);
203 return err;
190} 204}
191 205
192static void tcf_skbmod_cleanup(struct tc_action *a) 206static void tcf_skbmod_cleanup(struct tc_action *a)