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