Blame view

net/sched/act_skbedit.c 7.15 KB
ca9b0e27e   Alexander Duyck   pkt_action: add n...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * Copyright (c) 2008, Intel Corporation.
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms and conditions of the GNU General Public License,
   * version 2, as published by the Free Software Foundation.
   *
   * This program is distributed in the hope it will be useful, but WITHOUT
   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   * more details.
   *
   * You should have received a copy of the GNU General Public License along with
c057b190b   Jeff Kirsher   net/*: Fix FSF ad...
14
   * this program; if not, see <http://www.gnu.org/licenses/>.
ca9b0e27e   Alexander Duyck   pkt_action: add n...
15
16
17
18
19
20
21
22
23
24
25
26
27
28
   *
   * Author: Alexander Duyck <alexander.h.duyck@intel.com>
   */
  
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/skbuff.h>
  #include <linux/rtnetlink.h>
  #include <net/netlink.h>
  #include <net/pkt_sched.h>
  
  #include <linux/tc_act/tc_skbedit.h>
  #include <net/tc_act/tc_skbedit.h>
c7d03a00b   Alexey Dobriyan   netns: make struc...
29
  static unsigned int skbedit_net_id;
a85a970af   WANG Cong   net_sched: move t...
30
  static struct tc_action_ops act_skbedit_ops;
ddf97ccdd   WANG Cong   net_sched: add ne...
31

dc7f9f6e8   Eric Dumazet   net: sched: const...
32
  static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
ca9b0e27e   Alexander Duyck   pkt_action: add n...
33
34
  		       struct tcf_result *res)
  {
a85a970af   WANG Cong   net_sched: move t...
35
  	struct tcf_skbedit *d = to_skbedit(a);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
36
37
  
  	spin_lock(&d->tcf_lock);
9c4a4e488   Jamal Hadi Salim   net sched: action...
38
  	tcf_lastuse_update(&d->tcf_tm);
bfe0d0298   Eric Dumazet   net_sched: factor...
39
  	bstats_update(&d->tcf_bstats, skb);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
40
41
42
43
44
45
  
  	if (d->flags & SKBEDIT_F_PRIORITY)
  		skb->priority = d->priority;
  	if (d->flags & SKBEDIT_F_QUEUE_MAPPING &&
  	    skb->dev->real_num_tx_queues > d->queue_mapping)
  		skb_set_queue_mapping(skb, d->queue_mapping);
4fe77d82e   Antonio Quartulli   skbedit: allow th...
46
47
48
49
  	if (d->flags & SKBEDIT_F_MARK) {
  		skb->mark &= ~d->mask;
  		skb->mark |= d->mark & d->mask;
  	}
ff202ee1e   Jamal Hadi Salim   net sched actions...
50
51
  	if (d->flags & SKBEDIT_F_PTYPE)
  		skb->pkt_type = d->ptype;
ca9b0e27e   Alexander Duyck   pkt_action: add n...
52
53
54
55
56
57
58
59
60
  
  	spin_unlock(&d->tcf_lock);
  	return d->tcf_action;
  }
  
  static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
  	[TCA_SKBEDIT_PARMS]		= { .len = sizeof(struct tc_skbedit) },
  	[TCA_SKBEDIT_PRIORITY]		= { .len = sizeof(u32) },
  	[TCA_SKBEDIT_QUEUE_MAPPING]	= { .len = sizeof(u16) },
1c55d62e7   jamal   pkt_sched: skbedi...
61
  	[TCA_SKBEDIT_MARK]		= { .len = sizeof(u32) },
ff202ee1e   Jamal Hadi Salim   net sched actions...
62
  	[TCA_SKBEDIT_PTYPE]		= { .len = sizeof(u16) },
4fe77d82e   Antonio Quartulli   skbedit: allow th...
63
  	[TCA_SKBEDIT_MASK]		= { .len = sizeof(u32) },
ca9b0e27e   Alexander Duyck   pkt_action: add n...
64
  };
c1b52739e   Benjamin LaHaise   pkt_sched: namesp...
65
  static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
a85a970af   WANG Cong   net_sched: move t...
66
  			    struct nlattr *est, struct tc_action **a,
c1b52739e   Benjamin LaHaise   pkt_sched: namesp...
67
  			    int ovr, int bind)
ca9b0e27e   Alexander Duyck   pkt_action: add n...
68
  {
ddf97ccdd   WANG Cong   net_sched: add ne...
69
  	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
70
71
72
  	struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
  	struct tc_skbedit *parm;
  	struct tcf_skbedit *d;
4fe77d82e   Antonio Quartulli   skbedit: allow th...
73
  	u32 flags = 0, *priority = NULL, *mark = NULL, *mask = NULL;
ff202ee1e   Jamal Hadi Salim   net sched actions...
74
  	u16 *queue_mapping = NULL, *ptype = NULL;
b2313077e   WANG Cong   net_sched: make t...
75
76
  	bool exists = false;
  	int ret = 0, err;
ca9b0e27e   Alexander Duyck   pkt_action: add n...
77
78
79
  
  	if (nla == NULL)
  		return -EINVAL;
fceb6435e   Johannes Berg   netlink: pass ext...
80
  	err = nla_parse_nested(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy, NULL);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  	if (err < 0)
  		return err;
  
  	if (tb[TCA_SKBEDIT_PARMS] == NULL)
  		return -EINVAL;
  
  	if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
  		flags |= SKBEDIT_F_PRIORITY;
  		priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]);
  	}
  
  	if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
  		flags |= SKBEDIT_F_QUEUE_MAPPING;
  		queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
  	}
1c55d62e7   jamal   pkt_sched: skbedi...
96

ff202ee1e   Jamal Hadi Salim   net sched actions...
97
98
99
100
101
102
  	if (tb[TCA_SKBEDIT_PTYPE] != NULL) {
  		ptype = nla_data(tb[TCA_SKBEDIT_PTYPE]);
  		if (!skb_pkt_type_ok(*ptype))
  			return -EINVAL;
  		flags |= SKBEDIT_F_PTYPE;
  	}
1c55d62e7   jamal   pkt_sched: skbedi...
103
104
105
106
  	if (tb[TCA_SKBEDIT_MARK] != NULL) {
  		flags |= SKBEDIT_F_MARK;
  		mark = nla_data(tb[TCA_SKBEDIT_MARK]);
  	}
4fe77d82e   Antonio Quartulli   skbedit: allow th...
107
108
109
110
  	if (tb[TCA_SKBEDIT_MASK] != NULL) {
  		flags |= SKBEDIT_F_MASK;
  		mask = nla_data(tb[TCA_SKBEDIT_MASK]);
  	}
ca9b0e27e   Alexander Duyck   pkt_action: add n...
111
  	parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
65a206c01   Chris Mi   net/sched: Change...
112
  	exists = tcf_idr_check(tn, parm->index, a, bind);
5e1567aeb   Jamal Hadi Salim   net sched: skbedi...
113
114
115
116
  	if (exists && bind)
  		return 0;
  
  	if (!flags) {
869007543   Roman Mashak   net sched actions...
117
118
  		if (exists)
  			tcf_idr_release(*a, bind);
5e1567aeb   Jamal Hadi Salim   net sched: skbedi...
119
120
121
122
  		return -EINVAL;
  	}
  
  	if (!exists) {
65a206c01   Chris Mi   net/sched: Change...
123
124
  		ret = tcf_idr_create(tn, parm->index, est, a,
  				     &act_skbedit_ops, bind, false);
86062033f   WANG Cong   net_sched: act: h...
125
126
  		if (ret)
  			return ret;
ca9b0e27e   Alexander Duyck   pkt_action: add n...
127

a85a970af   WANG Cong   net_sched: move t...
128
  		d = to_skbedit(*a);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
129
130
  		ret = ACT_P_CREATED;
  	} else {
a85a970af   WANG Cong   net_sched: move t...
131
  		d = to_skbedit(*a);
65a206c01   Chris Mi   net/sched: Change...
132
  		tcf_idr_release(*a, bind);
1a29321ed   Jamal Hadi Salim   net_sched: act: D...
133
  		if (!ovr)
ca9b0e27e   Alexander Duyck   pkt_action: add n...
134
  			return -EEXIST;
ca9b0e27e   Alexander Duyck   pkt_action: add n...
135
136
137
138
139
140
141
142
143
  	}
  
  	spin_lock_bh(&d->tcf_lock);
  
  	d->flags = flags;
  	if (flags & SKBEDIT_F_PRIORITY)
  		d->priority = *priority;
  	if (flags & SKBEDIT_F_QUEUE_MAPPING)
  		d->queue_mapping = *queue_mapping;
1c55d62e7   jamal   pkt_sched: skbedi...
144
145
  	if (flags & SKBEDIT_F_MARK)
  		d->mark = *mark;
ff202ee1e   Jamal Hadi Salim   net sched actions...
146
147
  	if (flags & SKBEDIT_F_PTYPE)
  		d->ptype = *ptype;
4fe77d82e   Antonio Quartulli   skbedit: allow th...
148
149
150
151
  	/* default behaviour is to use all the bits */
  	d->mask = 0xffffffff;
  	if (flags & SKBEDIT_F_MASK)
  		d->mask = *mask;
1c55d62e7   jamal   pkt_sched: skbedi...
152

ca9b0e27e   Alexander Duyck   pkt_action: add n...
153
154
155
156
157
  	d->tcf_action = parm->action;
  
  	spin_unlock_bh(&d->tcf_lock);
  
  	if (ret == ACT_P_CREATED)
65a206c01   Chris Mi   net/sched: Change...
158
  		tcf_idr_insert(tn, *a);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
159
160
  	return ret;
  }
cc7ec456f   Eric Dumazet   net_sched: cleanups
161
162
  static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
  			    int bind, int ref)
ca9b0e27e   Alexander Duyck   pkt_action: add n...
163
164
  {
  	unsigned char *b = skb_tail_pointer(skb);
a85a970af   WANG Cong   net_sched: move t...
165
  	struct tcf_skbedit *d = to_skbedit(a);
1c40be12f   Eric Dumazet   net sched: fix so...
166
167
168
169
170
171
  	struct tc_skbedit opt = {
  		.index   = d->tcf_index,
  		.refcnt  = d->tcf_refcnt - ref,
  		.bindcnt = d->tcf_bindcnt - bind,
  		.action  = d->tcf_action,
  	};
ca9b0e27e   Alexander Duyck   pkt_action: add n...
172
  	struct tcf_t t;
1b34ec43c   David S. Miller   pkt_sched: Stop u...
173
174
175
  	if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt))
  		goto nla_put_failure;
  	if ((d->flags & SKBEDIT_F_PRIORITY) &&
61cc535de   Jamal Hadi Salim   net sched actions...
176
  	    nla_put_u32(skb, TCA_SKBEDIT_PRIORITY, d->priority))
1b34ec43c   David S. Miller   pkt_sched: Stop u...
177
178
  		goto nla_put_failure;
  	if ((d->flags & SKBEDIT_F_QUEUE_MAPPING) &&
61cc535de   Jamal Hadi Salim   net sched actions...
179
  	    nla_put_u16(skb, TCA_SKBEDIT_QUEUE_MAPPING, d->queue_mapping))
1b34ec43c   David S. Miller   pkt_sched: Stop u...
180
181
  		goto nla_put_failure;
  	if ((d->flags & SKBEDIT_F_MARK) &&
61cc535de   Jamal Hadi Salim   net sched actions...
182
  	    nla_put_u32(skb, TCA_SKBEDIT_MARK, d->mark))
1b34ec43c   David S. Miller   pkt_sched: Stop u...
183
  		goto nla_put_failure;
ff202ee1e   Jamal Hadi Salim   net sched actions...
184
  	if ((d->flags & SKBEDIT_F_PTYPE) &&
61cc535de   Jamal Hadi Salim   net sched actions...
185
  	    nla_put_u16(skb, TCA_SKBEDIT_PTYPE, d->ptype))
ff202ee1e   Jamal Hadi Salim   net sched actions...
186
  		goto nla_put_failure;
4fe77d82e   Antonio Quartulli   skbedit: allow th...
187
188
189
  	if ((d->flags & SKBEDIT_F_MASK) &&
  	    nla_put_u32(skb, TCA_SKBEDIT_MASK, d->mask))
  		goto nla_put_failure;
48d8ee169   Jamal Hadi Salim   net sched actions...
190
191
  
  	tcf_tm_dump(&t, &d->tcf_tm);
9854518ea   Nicolas Dichtel   sched: align nlat...
192
  	if (nla_put_64bit(skb, TCA_SKBEDIT_TM, sizeof(t), &t, TCA_SKBEDIT_PAD))
1b34ec43c   David S. Miller   pkt_sched: Stop u...
193
  		goto nla_put_failure;
ca9b0e27e   Alexander Duyck   pkt_action: add n...
194
195
196
197
198
199
  	return skb->len;
  
  nla_put_failure:
  	nlmsg_trim(skb, b);
  	return -1;
  }
ddf97ccdd   WANG Cong   net_sched: add ne...
200
201
  static int tcf_skbedit_walker(struct net *net, struct sk_buff *skb,
  			      struct netlink_callback *cb, int type,
a85a970af   WANG Cong   net_sched: move t...
202
  			      const struct tc_action_ops *ops)
ddf97ccdd   WANG Cong   net_sched: add ne...
203
204
  {
  	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
a85a970af   WANG Cong   net_sched: move t...
205
  	return tcf_generic_walker(tn, skb, cb, type, ops);
ddf97ccdd   WANG Cong   net_sched: add ne...
206
  }
a85a970af   WANG Cong   net_sched: move t...
207
  static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index)
ddf97ccdd   WANG Cong   net_sched: add ne...
208
209
  {
  	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
65a206c01   Chris Mi   net/sched: Change...
210
  	return tcf_idr_search(tn, a, index);
ddf97ccdd   WANG Cong   net_sched: add ne...
211
  }
ca9b0e27e   Alexander Duyck   pkt_action: add n...
212
213
  static struct tc_action_ops act_skbedit_ops = {
  	.kind		=	"skbedit",
ca9b0e27e   Alexander Duyck   pkt_action: add n...
214
  	.type		=	TCA_ACT_SKBEDIT,
ca9b0e27e   Alexander Duyck   pkt_action: add n...
215
216
217
  	.owner		=	THIS_MODULE,
  	.act		=	tcf_skbedit,
  	.dump		=	tcf_skbedit_dump,
ca9b0e27e   Alexander Duyck   pkt_action: add n...
218
  	.init		=	tcf_skbedit_init,
ddf97ccdd   WANG Cong   net_sched: add ne...
219
220
  	.walk		=	tcf_skbedit_walker,
  	.lookup		=	tcf_skbedit_search,
a85a970af   WANG Cong   net_sched: move t...
221
  	.size		=	sizeof(struct tcf_skbedit),
ddf97ccdd   WANG Cong   net_sched: add ne...
222
223
224
225
226
  };
  
  static __net_init int skbedit_init_net(struct net *net)
  {
  	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
c7e460ce5   Cong Wang   Revert "net_sched...
227
  	return tc_action_net_init(tn, &act_skbedit_ops);
ddf97ccdd   WANG Cong   net_sched: add ne...
228
229
230
231
232
233
234
235
236
237
238
239
240
241
  }
  
  static void __net_exit skbedit_exit_net(struct net *net)
  {
  	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
  
  	tc_action_net_exit(tn);
  }
  
  static struct pernet_operations skbedit_net_ops = {
  	.init = skbedit_init_net,
  	.exit = skbedit_exit_net,
  	.id   = &skbedit_net_id,
  	.size = sizeof(struct tc_action_net),
ca9b0e27e   Alexander Duyck   pkt_action: add n...
242
243
244
245
246
247
248
249
  };
  
  MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
  MODULE_DESCRIPTION("SKB Editing");
  MODULE_LICENSE("GPL");
  
  static int __init skbedit_init_module(void)
  {
ddf97ccdd   WANG Cong   net_sched: add ne...
250
  	return tcf_register_action(&act_skbedit_ops, &skbedit_net_ops);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
251
252
253
254
  }
  
  static void __exit skbedit_cleanup_module(void)
  {
ddf97ccdd   WANG Cong   net_sched: add ne...
255
  	tcf_unregister_action(&act_skbedit_ops, &skbedit_net_ops);
ca9b0e27e   Alexander Duyck   pkt_action: add n...
256
257
258
259
  }
  
  module_init(skbedit_init_module);
  module_exit(skbedit_cleanup_module);