1 /*
2  * lib/route/act/skbedit.c		skbedit action
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2015 Cong Wang <xiyou.wangcong@gmail.com>
10  */
11 
12 /**
13  * @ingroup act
14  * @defgroup act_skbedit SKB Editing
15  *
16  * @{
17  */
18 
19 #include <netlink-private/netlink.h>
20 #include <netlink-private/tc.h>
21 #include <netlink/netlink.h>
22 #include <netlink/attr.h>
23 #include <netlink/utils.h>
24 #include <netlink-private/route/tc-api.h>
25 #include <netlink/route/act/skbedit.h>
26 
27 static struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
28 	[TCA_SKBEDIT_PARMS]             = { .minlen = sizeof(struct tc_skbedit) },
29 	[TCA_SKBEDIT_PRIORITY]          = { .type = NLA_U32 },
30 	[TCA_SKBEDIT_QUEUE_MAPPING]     = { .type = NLA_U16 },
31 	[TCA_SKBEDIT_MARK]              = { .type = NLA_U32 },
32 };
33 
skbedit_msg_parser(struct rtnl_tc * tc,void * data)34 static int skbedit_msg_parser(struct rtnl_tc *tc, void *data)
35 {
36 	struct rtnl_skbedit *u = data;
37 	struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
38 	int err;
39 
40 	err = tca_parse(tb, TCA_SKBEDIT_MAX, tc, skbedit_policy);
41 	if (err < 0)
42 		return err;
43 
44 	if (!tb[TCA_SKBEDIT_PARMS])
45 		return -NLE_MISSING_ATTR;
46 
47 	u->s_flags = 0;
48 	if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
49 		u->s_flags |= SKBEDIT_F_PRIORITY;
50 		u->s_prio = nla_get_u32(tb[TCA_SKBEDIT_PRIORITY]);
51 	}
52 
53 	if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
54 		u->s_flags |= SKBEDIT_F_QUEUE_MAPPING;
55 		u->s_queue_mapping = nla_get_u16(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
56 	}
57 
58 	if (tb[TCA_SKBEDIT_MARK] != NULL) {
59 		u->s_flags |= SKBEDIT_F_MARK;
60 		u->s_mark = nla_get_u32(tb[TCA_SKBEDIT_MARK]);
61 	}
62 
63 	return 0;
64 }
65 
skbedit_free_data(struct rtnl_tc * tc,void * data)66 static void skbedit_free_data(struct rtnl_tc *tc, void *data)
67 {
68 }
69 
skbedit_clone(void * _dst,void * _src)70 static int skbedit_clone(void *_dst, void *_src)
71 {
72 	struct rtnl_skbedit *dst = _dst, *src = _src;
73 
74 	memcpy(dst, src, sizeof(*src));
75 	return 0;
76 }
77 
skbedit_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)78 static void skbedit_dump_line(struct rtnl_tc *tc, void *data,
79 			  struct nl_dump_params *p)
80 {
81 	struct rtnl_skbedit *u = data;
82 
83 	if (!u)
84 		return;
85 
86 	if (u->s_flags & SKBEDIT_F_PRIORITY)
87 		nl_dump(p, " priority %u", u->s_prio);
88 
89 	if (u->s_flags & SKBEDIT_F_MARK)
90 		nl_dump(p, " mark %u", u->s_mark);
91 
92 	if (u->s_flags & SKBEDIT_F_QUEUE_MAPPING)
93 		nl_dump(p, " queue_mapping %u", u->s_queue_mapping);
94 
95 	switch(u->s_parm.action){
96 	case TC_ACT_UNSPEC:
97 		nl_dump(p, " unspecified");
98 		break;
99 	case TC_ACT_PIPE:
100 		nl_dump(p, " pipe");
101 		break;
102 	case TC_ACT_STOLEN:
103 		nl_dump(p, " stolen");
104 		break;
105 	case TC_ACT_SHOT:
106 		nl_dump(p, " shot");
107 		break;
108 	case TC_ACT_QUEUED:
109 		nl_dump(p, " queued");
110 		break;
111 	case TC_ACT_REPEAT:
112 		nl_dump(p, " repeat");
113 		break;
114 	}
115 }
116 
skbedit_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)117 static void skbedit_dump_details(struct rtnl_tc *tc, void *data,
118 			     struct nl_dump_params *p)
119 {
120 }
121 
skbedit_dump_stats(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)122 static void skbedit_dump_stats(struct rtnl_tc *tc, void *data,
123 			   struct nl_dump_params *p)
124 {
125 	struct rtnl_skbedit *u = data;
126 
127 	if (!u)
128 		return;
129 	/* TODO */
130 }
131 
132 
skbedit_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)133 static int skbedit_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
134 {
135 	struct rtnl_skbedit *u = data;
136 
137 	if (!u)
138 		return 0;
139 
140 	NLA_PUT(msg, TCA_SKBEDIT_PARMS, sizeof(u->s_parm), &u->s_parm);
141 
142 	if (u->s_flags & SKBEDIT_F_MARK)
143 		NLA_PUT_U32(msg, TCA_SKBEDIT_MARK, u->s_mark);
144 
145 	if (u->s_flags & SKBEDIT_F_PRIORITY)
146 		NLA_PUT_U32(msg, TCA_SKBEDIT_PRIORITY, u->s_prio);
147 
148 	if (u->s_flags & SKBEDIT_F_QUEUE_MAPPING)
149 		NLA_PUT_U32(msg, TCA_SKBEDIT_QUEUE_MAPPING, u->s_queue_mapping);
150 
151 	return 0;
152 
153 nla_put_failure:
154 	return -NLE_NOMEM;
155 }
156 
157 /**
158  * @name Attribute Modifications
159  * @{
160  */
161 
rtnl_skbedit_set_action(struct rtnl_act * act,int action)162 int rtnl_skbedit_set_action(struct rtnl_act *act, int action)
163 {
164 	struct rtnl_skbedit *u;
165 
166 	if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
167 		return -NLE_NOMEM;
168 
169 	if (action > TC_ACT_REPEAT || action < TC_ACT_UNSPEC)
170 		return -NLE_INVAL;
171 
172 	u->s_parm.action = action;
173 	return 0;
174 }
175 
rtnl_skbedit_get_action(struct rtnl_act * act)176 int rtnl_skbedit_get_action(struct rtnl_act *act)
177 {
178 	struct rtnl_skbedit *u;
179 
180 	if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
181 		return -NLE_NOMEM;
182 	return u->s_parm.action;
183 }
184 
rtnl_skbedit_set_queue_mapping(struct rtnl_act * act,uint16_t index)185 int rtnl_skbedit_set_queue_mapping(struct rtnl_act *act, uint16_t index)
186 {
187 	struct rtnl_skbedit *u;
188 
189 	if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
190 		return -NLE_NOMEM;
191 
192 	u->s_queue_mapping = index;
193 	u->s_flags |= SKBEDIT_F_QUEUE_MAPPING;
194 	return 0;
195 }
196 
rtnl_skbedit_get_queue_mapping(struct rtnl_act * act,uint16_t * index)197 int rtnl_skbedit_get_queue_mapping(struct rtnl_act *act, uint16_t *index)
198 {
199 	struct rtnl_skbedit *u;
200 
201 	u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act));
202 	if (!u)
203 		return -NLE_NOMEM;
204 	if (!(u->s_flags & SKBEDIT_F_QUEUE_MAPPING))
205 		return -NLE_NOATTR;
206 
207 	*index = u->s_queue_mapping;
208 	return 0;
209 }
210 
rtnl_skbedit_set_mark(struct rtnl_act * act,uint32_t mark)211 int rtnl_skbedit_set_mark(struct rtnl_act *act, uint32_t mark)
212 {
213 	struct rtnl_skbedit *u;
214 
215 	if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
216 		return -NLE_NOMEM;
217 
218 	u->s_mark = mark;
219 	u->s_flags |= SKBEDIT_F_MARK;
220 	return 0;
221 }
222 
rtnl_skbedit_get_mark(struct rtnl_act * act,uint32_t * mark)223 int rtnl_skbedit_get_mark(struct rtnl_act *act, uint32_t *mark)
224 {
225 	struct rtnl_skbedit *u;
226 
227 	u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act));
228 	if (!u)
229 		return -NLE_NOMEM;
230 	if (!(u->s_flags & SKBEDIT_F_MARK))
231 		return -NLE_NOATTR;
232 
233 	*mark = u->s_mark;
234 	return 0;
235 }
236 
rtnl_skbedit_set_priority(struct rtnl_act * act,uint32_t prio)237 int rtnl_skbedit_set_priority(struct rtnl_act *act, uint32_t prio)
238 {
239 	struct rtnl_skbedit *u;
240 
241 	if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
242 		return -NLE_NOMEM;
243 
244 	u->s_prio = prio;
245 	u->s_flags |= SKBEDIT_F_PRIORITY;
246 	return 0;
247 }
248 
rtnl_skbedit_get_priority(struct rtnl_act * act,uint32_t * prio)249 int rtnl_skbedit_get_priority(struct rtnl_act *act, uint32_t *prio)
250 {
251 	struct rtnl_skbedit *u;
252 
253 	u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act));
254 	if (!u)
255 		return -NLE_NOMEM;
256 	if (!(u->s_flags & SKBEDIT_F_PRIORITY))
257 		return -NLE_NOATTR;
258 
259 	*prio = u->s_prio;
260 	return 0;
261 }
262 
263 /** @} */
264 
265 static struct rtnl_tc_ops skbedit_ops = {
266 	.to_kind		= "skbedit",
267 	.to_type		= RTNL_TC_TYPE_ACT,
268 	.to_size		= sizeof(struct rtnl_skbedit),
269 	.to_msg_parser		= skbedit_msg_parser,
270 	.to_free_data		= skbedit_free_data,
271 	.to_clone		= skbedit_clone,
272 	.to_msg_fill		= skbedit_msg_fill,
273 	.to_dump = {
274 	    [NL_DUMP_LINE]	= skbedit_dump_line,
275 	    [NL_DUMP_DETAILS]	= skbedit_dump_details,
276 	    [NL_DUMP_STATS]	= skbedit_dump_stats,
277 	},
278 };
279 
skbedit_init(void)280 static void __init skbedit_init(void)
281 {
282 	rtnl_tc_register(&skbedit_ops);
283 }
284 
skbedit_exit(void)285 static void __exit skbedit_exit(void)
286 {
287 	rtnl_tc_unregister(&skbedit_ops);
288 }
289 
290 /** @} */
291