xref: /openbmc/linux/net/sched/act_skbedit.c (revision c749cdda9089eb1fdb6a9ab98f945124d12f2595)
1ca9b0e27SAlexander Duyck /*
2ca9b0e27SAlexander Duyck  * Copyright (c) 2008, Intel Corporation.
3ca9b0e27SAlexander Duyck  *
4ca9b0e27SAlexander Duyck  * This program is free software; you can redistribute it and/or modify it
5ca9b0e27SAlexander Duyck  * under the terms and conditions of the GNU General Public License,
6ca9b0e27SAlexander Duyck  * version 2, as published by the Free Software Foundation.
7ca9b0e27SAlexander Duyck  *
8ca9b0e27SAlexander Duyck  * This program is distributed in the hope it will be useful, but WITHOUT
9ca9b0e27SAlexander Duyck  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10ca9b0e27SAlexander Duyck  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11ca9b0e27SAlexander Duyck  * more details.
12ca9b0e27SAlexander Duyck  *
13ca9b0e27SAlexander Duyck  * You should have received a copy of the GNU General Public License along with
14c057b190SJeff Kirsher  * this program; if not, see <http://www.gnu.org/licenses/>.
15ca9b0e27SAlexander Duyck  *
16ca9b0e27SAlexander Duyck  * Author: Alexander Duyck <alexander.h.duyck@intel.com>
17ca9b0e27SAlexander Duyck  */
18ca9b0e27SAlexander Duyck 
19ca9b0e27SAlexander Duyck #include <linux/module.h>
20ca9b0e27SAlexander Duyck #include <linux/init.h>
21ca9b0e27SAlexander Duyck #include <linux/kernel.h>
22ca9b0e27SAlexander Duyck #include <linux/skbuff.h>
23ca9b0e27SAlexander Duyck #include <linux/rtnetlink.h>
24ca9b0e27SAlexander Duyck #include <net/netlink.h>
25ca9b0e27SAlexander Duyck #include <net/pkt_sched.h>
26e7e3728bSQiaobin Fu #include <net/ip.h>
27e7e3728bSQiaobin Fu #include <net/ipv6.h>
28e7e3728bSQiaobin Fu #include <net/dsfield.h>
29ca9b0e27SAlexander Duyck 
30ca9b0e27SAlexander Duyck #include <linux/tc_act/tc_skbedit.h>
31ca9b0e27SAlexander Duyck #include <net/tc_act/tc_skbedit.h>
32ca9b0e27SAlexander Duyck 
33c7d03a00SAlexey Dobriyan static unsigned int skbedit_net_id;
34a85a970aSWANG Cong static struct tc_action_ops act_skbedit_ops;
35ddf97ccdSWANG Cong 
36dc7f9f6eSEric Dumazet static int tcf_skbedit(struct sk_buff *skb, const struct tc_action *a,
37ca9b0e27SAlexander Duyck 		       struct tcf_result *res)
38ca9b0e27SAlexander Duyck {
39a85a970aSWANG Cong 	struct tcf_skbedit *d = to_skbedit(a);
40*c749cddaSDavide Caratti 	struct tcf_skbedit_params *params;
41*c749cddaSDavide Caratti 	int action;
42ca9b0e27SAlexander Duyck 
439c4a4e48SJamal Hadi Salim 	tcf_lastuse_update(&d->tcf_tm);
446f3dfb0dSDavide Caratti 	bstats_cpu_update(this_cpu_ptr(d->common.cpu_bstats), skb);
45ca9b0e27SAlexander Duyck 
46*c749cddaSDavide Caratti 	rcu_read_lock();
47*c749cddaSDavide Caratti 	params = rcu_dereference(d->params);
48*c749cddaSDavide Caratti 	action = READ_ONCE(d->tcf_action);
49*c749cddaSDavide Caratti 
50*c749cddaSDavide Caratti 	if (params->flags & SKBEDIT_F_PRIORITY)
51*c749cddaSDavide Caratti 		skb->priority = params->priority;
52*c749cddaSDavide Caratti 	if (params->flags & SKBEDIT_F_INHERITDSFIELD) {
53e7e3728bSQiaobin Fu 		int wlen = skb_network_offset(skb);
54e7e3728bSQiaobin Fu 
55e7e3728bSQiaobin Fu 		switch (tc_skb_protocol(skb)) {
56e7e3728bSQiaobin Fu 		case htons(ETH_P_IP):
57e7e3728bSQiaobin Fu 			wlen += sizeof(struct iphdr);
58e7e3728bSQiaobin Fu 			if (!pskb_may_pull(skb, wlen))
59e7e3728bSQiaobin Fu 				goto err;
60e7e3728bSQiaobin Fu 			skb->priority = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
61e7e3728bSQiaobin Fu 			break;
62e7e3728bSQiaobin Fu 
63e7e3728bSQiaobin Fu 		case htons(ETH_P_IPV6):
64e7e3728bSQiaobin Fu 			wlen += sizeof(struct ipv6hdr);
65e7e3728bSQiaobin Fu 			if (!pskb_may_pull(skb, wlen))
66e7e3728bSQiaobin Fu 				goto err;
67e7e3728bSQiaobin Fu 			skb->priority = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
68e7e3728bSQiaobin Fu 			break;
69e7e3728bSQiaobin Fu 		}
70e7e3728bSQiaobin Fu 	}
71*c749cddaSDavide Caratti 	if (params->flags & SKBEDIT_F_QUEUE_MAPPING &&
72*c749cddaSDavide Caratti 	    skb->dev->real_num_tx_queues > params->queue_mapping)
73*c749cddaSDavide Caratti 		skb_set_queue_mapping(skb, params->queue_mapping);
74*c749cddaSDavide Caratti 	if (params->flags & SKBEDIT_F_MARK) {
75*c749cddaSDavide Caratti 		skb->mark &= ~params->mask;
76*c749cddaSDavide Caratti 		skb->mark |= params->mark & params->mask;
774fe77d82SAntonio Quartulli 	}
78*c749cddaSDavide Caratti 	if (params->flags & SKBEDIT_F_PTYPE)
79*c749cddaSDavide Caratti 		skb->pkt_type = params->ptype;
80ca9b0e27SAlexander Duyck 
81*c749cddaSDavide Caratti unlock:
82*c749cddaSDavide Caratti 	rcu_read_unlock();
83*c749cddaSDavide Caratti 	return action;
84e7e3728bSQiaobin Fu err:
856f3dfb0dSDavide Caratti 	qstats_drop_inc(this_cpu_ptr(d->common.cpu_qstats));
86*c749cddaSDavide Caratti 	action = TC_ACT_SHOT;
87*c749cddaSDavide Caratti 	goto unlock;
88ca9b0e27SAlexander Duyck }
89ca9b0e27SAlexander Duyck 
90ca9b0e27SAlexander Duyck static const struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
91ca9b0e27SAlexander Duyck 	[TCA_SKBEDIT_PARMS]		= { .len = sizeof(struct tc_skbedit) },
92ca9b0e27SAlexander Duyck 	[TCA_SKBEDIT_PRIORITY]		= { .len = sizeof(u32) },
93ca9b0e27SAlexander Duyck 	[TCA_SKBEDIT_QUEUE_MAPPING]	= { .len = sizeof(u16) },
941c55d62eSjamal 	[TCA_SKBEDIT_MARK]		= { .len = sizeof(u32) },
95ff202ee1SJamal Hadi Salim 	[TCA_SKBEDIT_PTYPE]		= { .len = sizeof(u16) },
964fe77d82SAntonio Quartulli 	[TCA_SKBEDIT_MASK]		= { .len = sizeof(u32) },
97e7e3728bSQiaobin Fu 	[TCA_SKBEDIT_FLAGS]		= { .len = sizeof(u64) },
98ca9b0e27SAlexander Duyck };
99ca9b0e27SAlexander Duyck 
100c1b52739SBenjamin LaHaise static int tcf_skbedit_init(struct net *net, struct nlattr *nla,
101a85a970aSWANG Cong 			    struct nlattr *est, struct tc_action **a,
102789871bbSVlad Buslov 			    int ovr, int bind, bool rtnl_held,
103789871bbSVlad Buslov 			    struct netlink_ext_ack *extack)
104ca9b0e27SAlexander Duyck {
105ddf97ccdSWANG Cong 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
106*c749cddaSDavide Caratti 	struct tcf_skbedit_params *params_old, *params_new;
107ca9b0e27SAlexander Duyck 	struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
108ca9b0e27SAlexander Duyck 	struct tc_skbedit *parm;
109ca9b0e27SAlexander Duyck 	struct tcf_skbedit *d;
1104fe77d82SAntonio Quartulli 	u32 flags = 0, *priority = NULL, *mark = NULL, *mask = NULL;
111ff202ee1SJamal Hadi Salim 	u16 *queue_mapping = NULL, *ptype = NULL;
112b2313077SWANG Cong 	bool exists = false;
113b2313077SWANG Cong 	int ret = 0, err;
114ca9b0e27SAlexander Duyck 
115ca9b0e27SAlexander Duyck 	if (nla == NULL)
116ca9b0e27SAlexander Duyck 		return -EINVAL;
117ca9b0e27SAlexander Duyck 
118fceb6435SJohannes Berg 	err = nla_parse_nested(tb, TCA_SKBEDIT_MAX, nla, skbedit_policy, NULL);
119ca9b0e27SAlexander Duyck 	if (err < 0)
120ca9b0e27SAlexander Duyck 		return err;
121ca9b0e27SAlexander Duyck 
122ca9b0e27SAlexander Duyck 	if (tb[TCA_SKBEDIT_PARMS] == NULL)
123ca9b0e27SAlexander Duyck 		return -EINVAL;
124ca9b0e27SAlexander Duyck 
125ca9b0e27SAlexander Duyck 	if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
126ca9b0e27SAlexander Duyck 		flags |= SKBEDIT_F_PRIORITY;
127ca9b0e27SAlexander Duyck 		priority = nla_data(tb[TCA_SKBEDIT_PRIORITY]);
128ca9b0e27SAlexander Duyck 	}
129ca9b0e27SAlexander Duyck 
130ca9b0e27SAlexander Duyck 	if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
131ca9b0e27SAlexander Duyck 		flags |= SKBEDIT_F_QUEUE_MAPPING;
132ca9b0e27SAlexander Duyck 		queue_mapping = nla_data(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
133ca9b0e27SAlexander Duyck 	}
1341c55d62eSjamal 
135ff202ee1SJamal Hadi Salim 	if (tb[TCA_SKBEDIT_PTYPE] != NULL) {
136ff202ee1SJamal Hadi Salim 		ptype = nla_data(tb[TCA_SKBEDIT_PTYPE]);
137ff202ee1SJamal Hadi Salim 		if (!skb_pkt_type_ok(*ptype))
138ff202ee1SJamal Hadi Salim 			return -EINVAL;
139ff202ee1SJamal Hadi Salim 		flags |= SKBEDIT_F_PTYPE;
140ff202ee1SJamal Hadi Salim 	}
141ff202ee1SJamal Hadi Salim 
1421c55d62eSjamal 	if (tb[TCA_SKBEDIT_MARK] != NULL) {
1431c55d62eSjamal 		flags |= SKBEDIT_F_MARK;
1441c55d62eSjamal 		mark = nla_data(tb[TCA_SKBEDIT_MARK]);
1451c55d62eSjamal 	}
1461c55d62eSjamal 
1474fe77d82SAntonio Quartulli 	if (tb[TCA_SKBEDIT_MASK] != NULL) {
1484fe77d82SAntonio Quartulli 		flags |= SKBEDIT_F_MASK;
1494fe77d82SAntonio Quartulli 		mask = nla_data(tb[TCA_SKBEDIT_MASK]);
1504fe77d82SAntonio Quartulli 	}
1514fe77d82SAntonio Quartulli 
152e7e3728bSQiaobin Fu 	if (tb[TCA_SKBEDIT_FLAGS] != NULL) {
153e7e3728bSQiaobin Fu 		u64 *pure_flags = nla_data(tb[TCA_SKBEDIT_FLAGS]);
154e7e3728bSQiaobin Fu 
155e7e3728bSQiaobin Fu 		if (*pure_flags & SKBEDIT_F_INHERITDSFIELD)
156e7e3728bSQiaobin Fu 			flags |= SKBEDIT_F_INHERITDSFIELD;
157e7e3728bSQiaobin Fu 	}
158e7e3728bSQiaobin Fu 
159ca9b0e27SAlexander Duyck 	parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
160ca9b0e27SAlexander Duyck 
1610190c1d4SVlad Buslov 	err = tcf_idr_check_alloc(tn, &parm->index, a, bind);
1620190c1d4SVlad Buslov 	if (err < 0)
1630190c1d4SVlad Buslov 		return err;
1640190c1d4SVlad Buslov 	exists = err;
1655e1567aeSJamal Hadi Salim 	if (exists && bind)
1665e1567aeSJamal Hadi Salim 		return 0;
1675e1567aeSJamal Hadi Salim 
1685e1567aeSJamal Hadi Salim 	if (!flags) {
169af5d0184SRoman Mashak 		if (exists)
17065a206c0SChris Mi 			tcf_idr_release(*a, bind);
1710190c1d4SVlad Buslov 		else
1720190c1d4SVlad Buslov 			tcf_idr_cleanup(tn, parm->index);
1735e1567aeSJamal Hadi Salim 		return -EINVAL;
1745e1567aeSJamal Hadi Salim 	}
1755e1567aeSJamal Hadi Salim 
1765e1567aeSJamal Hadi Salim 	if (!exists) {
17765a206c0SChris Mi 		ret = tcf_idr_create(tn, parm->index, est, a,
1786f3dfb0dSDavide Caratti 				     &act_skbedit_ops, bind, true);
1790190c1d4SVlad Buslov 		if (ret) {
1800190c1d4SVlad Buslov 			tcf_idr_cleanup(tn, parm->index);
18186062033SWANG Cong 			return ret;
1820190c1d4SVlad Buslov 		}
183ca9b0e27SAlexander Duyck 
184a85a970aSWANG Cong 		d = to_skbedit(*a);
185ca9b0e27SAlexander Duyck 		ret = ACT_P_CREATED;
186ca9b0e27SAlexander Duyck 	} else {
187a85a970aSWANG Cong 		d = to_skbedit(*a);
1884e8ddd7fSVlad Buslov 		if (!ovr) {
18965a206c0SChris Mi 			tcf_idr_release(*a, bind);
190ca9b0e27SAlexander Duyck 			return -EEXIST;
191ca9b0e27SAlexander Duyck 		}
1924e8ddd7fSVlad Buslov 	}
193ca9b0e27SAlexander Duyck 
194*c749cddaSDavide Caratti 	ASSERT_RTNL();
195ca9b0e27SAlexander Duyck 
196*c749cddaSDavide Caratti 	params_new = kzalloc(sizeof(*params_new), GFP_KERNEL);
197*c749cddaSDavide Caratti 	if (unlikely(!params_new)) {
198*c749cddaSDavide Caratti 		if (ret == ACT_P_CREATED)
199*c749cddaSDavide Caratti 			tcf_idr_release(*a, bind);
200*c749cddaSDavide Caratti 		return -ENOMEM;
201*c749cddaSDavide Caratti 	}
202*c749cddaSDavide Caratti 
203*c749cddaSDavide Caratti 	params_new->flags = flags;
204ca9b0e27SAlexander Duyck 	if (flags & SKBEDIT_F_PRIORITY)
205*c749cddaSDavide Caratti 		params_new->priority = *priority;
206ca9b0e27SAlexander Duyck 	if (flags & SKBEDIT_F_QUEUE_MAPPING)
207*c749cddaSDavide Caratti 		params_new->queue_mapping = *queue_mapping;
2081c55d62eSjamal 	if (flags & SKBEDIT_F_MARK)
209*c749cddaSDavide Caratti 		params_new->mark = *mark;
210ff202ee1SJamal Hadi Salim 	if (flags & SKBEDIT_F_PTYPE)
211*c749cddaSDavide Caratti 		params_new->ptype = *ptype;
2124fe77d82SAntonio Quartulli 	/* default behaviour is to use all the bits */
213*c749cddaSDavide Caratti 	params_new->mask = 0xffffffff;
2144fe77d82SAntonio Quartulli 	if (flags & SKBEDIT_F_MASK)
215*c749cddaSDavide Caratti 		params_new->mask = *mask;
2161c55d62eSjamal 
217ca9b0e27SAlexander Duyck 	d->tcf_action = parm->action;
218*c749cddaSDavide Caratti 	params_old = rtnl_dereference(d->params);
219*c749cddaSDavide Caratti 	rcu_assign_pointer(d->params, params_new);
220*c749cddaSDavide Caratti 	if (params_old)
221*c749cddaSDavide Caratti 		kfree_rcu(params_old, rcu);
222ca9b0e27SAlexander Duyck 
223ca9b0e27SAlexander Duyck 	if (ret == ACT_P_CREATED)
22465a206c0SChris Mi 		tcf_idr_insert(tn, *a);
225ca9b0e27SAlexander Duyck 	return ret;
226ca9b0e27SAlexander Duyck }
227ca9b0e27SAlexander Duyck 
228cc7ec456SEric Dumazet static int tcf_skbedit_dump(struct sk_buff *skb, struct tc_action *a,
229ca9b0e27SAlexander Duyck 			    int bind, int ref)
230ca9b0e27SAlexander Duyck {
231ca9b0e27SAlexander Duyck 	unsigned char *b = skb_tail_pointer(skb);
232a85a970aSWANG Cong 	struct tcf_skbedit *d = to_skbedit(a);
233*c749cddaSDavide Caratti 	struct tcf_skbedit_params *params;
2341c40be12SEric Dumazet 	struct tc_skbedit opt = {
2351c40be12SEric Dumazet 		.index   = d->tcf_index,
236036bb443SVlad Buslov 		.refcnt  = refcount_read(&d->tcf_refcnt) - ref,
237036bb443SVlad Buslov 		.bindcnt = atomic_read(&d->tcf_bindcnt) - bind,
2381c40be12SEric Dumazet 		.action  = d->tcf_action,
2391c40be12SEric Dumazet 	};
240e7e3728bSQiaobin Fu 	u64 pure_flags = 0;
241*c749cddaSDavide Caratti 	struct tcf_t t;
242*c749cddaSDavide Caratti 
243*c749cddaSDavide Caratti 	params = rtnl_dereference(d->params);
244ca9b0e27SAlexander Duyck 
2451b34ec43SDavid S. Miller 	if (nla_put(skb, TCA_SKBEDIT_PARMS, sizeof(opt), &opt))
2461b34ec43SDavid S. Miller 		goto nla_put_failure;
247*c749cddaSDavide Caratti 	if ((params->flags & SKBEDIT_F_PRIORITY) &&
248*c749cddaSDavide Caratti 	    nla_put_u32(skb, TCA_SKBEDIT_PRIORITY, params->priority))
2491b34ec43SDavid S. Miller 		goto nla_put_failure;
250*c749cddaSDavide Caratti 	if ((params->flags & SKBEDIT_F_QUEUE_MAPPING) &&
251*c749cddaSDavide Caratti 	    nla_put_u16(skb, TCA_SKBEDIT_QUEUE_MAPPING, params->queue_mapping))
2521b34ec43SDavid S. Miller 		goto nla_put_failure;
253*c749cddaSDavide Caratti 	if ((params->flags & SKBEDIT_F_MARK) &&
254*c749cddaSDavide Caratti 	    nla_put_u32(skb, TCA_SKBEDIT_MARK, params->mark))
2551b34ec43SDavid S. Miller 		goto nla_put_failure;
256*c749cddaSDavide Caratti 	if ((params->flags & SKBEDIT_F_PTYPE) &&
257*c749cddaSDavide Caratti 	    nla_put_u16(skb, TCA_SKBEDIT_PTYPE, params->ptype))
258ff202ee1SJamal Hadi Salim 		goto nla_put_failure;
259*c749cddaSDavide Caratti 	if ((params->flags & SKBEDIT_F_MASK) &&
260*c749cddaSDavide Caratti 	    nla_put_u32(skb, TCA_SKBEDIT_MASK, params->mask))
2614fe77d82SAntonio Quartulli 		goto nla_put_failure;
262*c749cddaSDavide Caratti 	if (params->flags & SKBEDIT_F_INHERITDSFIELD)
263e7e3728bSQiaobin Fu 		pure_flags |= SKBEDIT_F_INHERITDSFIELD;
264e7e3728bSQiaobin Fu 	if (pure_flags != 0 &&
265e7e3728bSQiaobin Fu 	    nla_put(skb, TCA_SKBEDIT_FLAGS, sizeof(pure_flags), &pure_flags))
266e7e3728bSQiaobin Fu 		goto nla_put_failure;
26748d8ee16SJamal Hadi Salim 
26848d8ee16SJamal Hadi Salim 	tcf_tm_dump(&t, &d->tcf_tm);
2699854518eSNicolas Dichtel 	if (nla_put_64bit(skb, TCA_SKBEDIT_TM, sizeof(t), &t, TCA_SKBEDIT_PAD))
2701b34ec43SDavid S. Miller 		goto nla_put_failure;
271ca9b0e27SAlexander Duyck 	return skb->len;
272ca9b0e27SAlexander Duyck 
273ca9b0e27SAlexander Duyck nla_put_failure:
274ca9b0e27SAlexander Duyck 	nlmsg_trim(skb, b);
275ca9b0e27SAlexander Duyck 	return -1;
276ca9b0e27SAlexander Duyck }
277ca9b0e27SAlexander Duyck 
278*c749cddaSDavide Caratti static void tcf_skbedit_cleanup(struct tc_action *a)
279*c749cddaSDavide Caratti {
280*c749cddaSDavide Caratti 	struct tcf_skbedit *d = to_skbedit(a);
281*c749cddaSDavide Caratti 	struct tcf_skbedit_params *params;
282*c749cddaSDavide Caratti 
283*c749cddaSDavide Caratti 	params = rcu_dereference_protected(d->params, 1);
284*c749cddaSDavide Caratti 	if (params)
285*c749cddaSDavide Caratti 		kfree_rcu(params, rcu);
286*c749cddaSDavide Caratti }
287*c749cddaSDavide Caratti 
288ddf97ccdSWANG Cong static int tcf_skbedit_walker(struct net *net, struct sk_buff *skb,
289ddf97ccdSWANG Cong 			      struct netlink_callback *cb, int type,
29041780105SAlexander Aring 			      const struct tc_action_ops *ops,
29141780105SAlexander Aring 			      struct netlink_ext_ack *extack)
292ddf97ccdSWANG Cong {
293ddf97ccdSWANG Cong 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
294ddf97ccdSWANG Cong 
295b3620145SAlexander Aring 	return tcf_generic_walker(tn, skb, cb, type, ops, extack);
296ddf97ccdSWANG Cong }
297ddf97ccdSWANG Cong 
298331a9295SAlexander Aring static int tcf_skbedit_search(struct net *net, struct tc_action **a, u32 index,
299331a9295SAlexander Aring 			      struct netlink_ext_ack *extack)
300ddf97ccdSWANG Cong {
301ddf97ccdSWANG Cong 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
302ddf97ccdSWANG Cong 
30365a206c0SChris Mi 	return tcf_idr_search(tn, a, index);
304ddf97ccdSWANG Cong }
305ddf97ccdSWANG Cong 
306b409074eSVlad Buslov static int tcf_skbedit_delete(struct net *net, u32 index)
307b409074eSVlad Buslov {
308b409074eSVlad Buslov 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
309b409074eSVlad Buslov 
310b409074eSVlad Buslov 	return tcf_idr_delete_index(tn, index);
311b409074eSVlad Buslov }
312b409074eSVlad Buslov 
313ca9b0e27SAlexander Duyck static struct tc_action_ops act_skbedit_ops = {
314ca9b0e27SAlexander Duyck 	.kind		=	"skbedit",
315ca9b0e27SAlexander Duyck 	.type		=	TCA_ACT_SKBEDIT,
316ca9b0e27SAlexander Duyck 	.owner		=	THIS_MODULE,
317ca9b0e27SAlexander Duyck 	.act		=	tcf_skbedit,
318ca9b0e27SAlexander Duyck 	.dump		=	tcf_skbedit_dump,
319ca9b0e27SAlexander Duyck 	.init		=	tcf_skbedit_init,
320*c749cddaSDavide Caratti 	.cleanup	=	tcf_skbedit_cleanup,
321ddf97ccdSWANG Cong 	.walk		=	tcf_skbedit_walker,
322ddf97ccdSWANG Cong 	.lookup		=	tcf_skbedit_search,
323b409074eSVlad Buslov 	.delete		=	tcf_skbedit_delete,
324a85a970aSWANG Cong 	.size		=	sizeof(struct tcf_skbedit),
325ddf97ccdSWANG Cong };
326ddf97ccdSWANG Cong 
327ddf97ccdSWANG Cong static __net_init int skbedit_init_net(struct net *net)
328ddf97ccdSWANG Cong {
329ddf97ccdSWANG Cong 	struct tc_action_net *tn = net_generic(net, skbedit_net_id);
330ddf97ccdSWANG Cong 
331c7e460ceSCong Wang 	return tc_action_net_init(tn, &act_skbedit_ops);
332ddf97ccdSWANG Cong }
333ddf97ccdSWANG Cong 
334039af9c6SCong Wang static void __net_exit skbedit_exit_net(struct list_head *net_list)
335ddf97ccdSWANG Cong {
336039af9c6SCong Wang 	tc_action_net_exit(net_list, skbedit_net_id);
337ddf97ccdSWANG Cong }
338ddf97ccdSWANG Cong 
339ddf97ccdSWANG Cong static struct pernet_operations skbedit_net_ops = {
340ddf97ccdSWANG Cong 	.init = skbedit_init_net,
341039af9c6SCong Wang 	.exit_batch = skbedit_exit_net,
342ddf97ccdSWANG Cong 	.id   = &skbedit_net_id,
343ddf97ccdSWANG Cong 	.size = sizeof(struct tc_action_net),
344ca9b0e27SAlexander Duyck };
345ca9b0e27SAlexander Duyck 
346ca9b0e27SAlexander Duyck MODULE_AUTHOR("Alexander Duyck, <alexander.h.duyck@intel.com>");
347ca9b0e27SAlexander Duyck MODULE_DESCRIPTION("SKB Editing");
348ca9b0e27SAlexander Duyck MODULE_LICENSE("GPL");
349ca9b0e27SAlexander Duyck 
350ca9b0e27SAlexander Duyck static int __init skbedit_init_module(void)
351ca9b0e27SAlexander Duyck {
352ddf97ccdSWANG Cong 	return tcf_register_action(&act_skbedit_ops, &skbedit_net_ops);
353ca9b0e27SAlexander Duyck }
354ca9b0e27SAlexander Duyck 
355ca9b0e27SAlexander Duyck static void __exit skbedit_cleanup_module(void)
356ca9b0e27SAlexander Duyck {
357ddf97ccdSWANG Cong 	tcf_unregister_action(&act_skbedit_ops, &skbedit_net_ops);
358ca9b0e27SAlexander Duyck }
359ca9b0e27SAlexander Duyck 
360ca9b0e27SAlexander Duyck module_init(skbedit_init_module);
361ca9b0e27SAlexander Duyck module_exit(skbedit_cleanup_module);
362