]>
Commit | Line | Data |
---|---|---|
d57639a4 AV |
1 | /* |
2 | * m_tunnel_key.c ip tunnel manipulation module | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; either version | |
7 | * 2 of the License, or (at your option) any later version. | |
8 | * | |
9 | * Authors: Amir Vadai <amir@vadai.me> | |
10 | */ | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <unistd.h> | |
15 | #include <string.h> | |
16 | #include <linux/if_ether.h> | |
17 | #include "utils.h" | |
18 | #include "rt_names.h" | |
19 | #include "tc_util.h" | |
20 | #include <linux/tc_act/tc_tunnel_key.h> | |
21 | ||
22 | static void explain(void) | |
23 | { | |
24 | fprintf(stderr, "Usage: tunnel_key unset\n"); | |
50907a82 JB |
25 | fprintf(stderr, " tunnel_key set <TUNNEL_KEY>\n"); |
26 | fprintf(stderr, | |
27 | "Where TUNNEL_KEY is a combination of:\n" | |
28 | "id <TUNNELID> (mandatory)\n" | |
29 | "src_ip <IP> (mandatory)\n" | |
30 | "dst_ip <IP> (mandatory)\n" | |
59eb271d JB |
31 | "dst_port <UDP_PORT>\n" |
32 | "csum | nocsum (default is \"csum\")\n"); | |
d57639a4 AV |
33 | } |
34 | ||
35 | static void usage(void) | |
36 | { | |
37 | explain(); | |
38 | exit(-1); | |
39 | } | |
40 | ||
41 | static int tunnel_key_parse_ip_addr(const char *str, int addr4_type, | |
42 | int addr6_type, struct nlmsghdr *n) | |
43 | { | |
44 | inet_prefix addr; | |
45 | int ret; | |
46 | ||
47 | ret = get_addr(&addr, str, AF_UNSPEC); | |
48 | if (ret) | |
49 | return ret; | |
50 | ||
51 | addattr_l(n, MAX_MSG, addr.family == AF_INET ? addr4_type : addr6_type, | |
52 | addr.data, addr.bytelen); | |
53 | ||
54 | return 0; | |
55 | } | |
56 | ||
57 | static int tunnel_key_parse_key_id(const char *str, int type, | |
58 | struct nlmsghdr *n) | |
59 | { | |
60 | __be32 key_id; | |
61 | int ret; | |
62 | ||
63 | ret = get_be32(&key_id, str, 10); | |
64 | if (!ret) | |
65 | addattr32(n, MAX_MSG, type, key_id); | |
66 | ||
67 | return ret; | |
68 | } | |
69 | ||
449c709c HHZ |
70 | static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n) |
71 | { | |
72 | int ret; | |
73 | __be16 dst_port; | |
74 | ||
75 | ret = get_be16(&dst_port, str, 10); | |
76 | if (ret) | |
77 | return -1; | |
78 | ||
79 | addattr16(n, MAX_MSG, type, dst_port); | |
80 | ||
81 | return 0; | |
82 | } | |
83 | ||
d57639a4 AV |
84 | static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p, |
85 | int tca_id, struct nlmsghdr *n) | |
86 | { | |
e67aba55 | 87 | struct tc_tunnel_key parm = {}; |
d57639a4 AV |
88 | char **argv = *argv_p; |
89 | int argc = *argc_p; | |
90 | struct rtattr *tail; | |
91 | int action = 0; | |
92 | int ret; | |
93 | int has_src_ip = 0; | |
94 | int has_dst_ip = 0; | |
95 | int has_key_id = 0; | |
59eb271d | 96 | int csum = 1; |
d57639a4 AV |
97 | |
98 | if (matches(*argv, "tunnel_key") != 0) | |
99 | return -1; | |
100 | ||
101 | tail = NLMSG_TAIL(n); | |
102 | addattr_l(n, MAX_MSG, tca_id, NULL, 0); | |
103 | ||
104 | NEXT_ARG(); | |
105 | ||
106 | while (argc > 0) { | |
107 | if (matches(*argv, "unset") == 0) { | |
108 | if (action) { | |
109 | fprintf(stderr, "unexpected \"%s\" - action already specified\n", | |
110 | *argv); | |
111 | explain(); | |
112 | return -1; | |
113 | } | |
114 | action = TCA_TUNNEL_KEY_ACT_RELEASE; | |
115 | } else if (matches(*argv, "set") == 0) { | |
116 | if (action) { | |
117 | fprintf(stderr, "unexpected \"%s\" - action already specified\n", | |
118 | *argv); | |
119 | explain(); | |
120 | return -1; | |
121 | } | |
122 | action = TCA_TUNNEL_KEY_ACT_SET; | |
123 | } else if (matches(*argv, "src_ip") == 0) { | |
124 | NEXT_ARG(); | |
125 | ret = tunnel_key_parse_ip_addr(*argv, | |
126 | TCA_TUNNEL_KEY_ENC_IPV4_SRC, | |
127 | TCA_TUNNEL_KEY_ENC_IPV6_SRC, | |
128 | n); | |
129 | if (ret < 0) { | |
130 | fprintf(stderr, "Illegal \"src_ip\"\n"); | |
131 | return -1; | |
132 | } | |
133 | has_src_ip = 1; | |
134 | } else if (matches(*argv, "dst_ip") == 0) { | |
135 | NEXT_ARG(); | |
136 | ret = tunnel_key_parse_ip_addr(*argv, | |
137 | TCA_TUNNEL_KEY_ENC_IPV4_DST, | |
138 | TCA_TUNNEL_KEY_ENC_IPV6_DST, | |
139 | n); | |
140 | if (ret < 0) { | |
141 | fprintf(stderr, "Illegal \"dst_ip\"\n"); | |
142 | return -1; | |
143 | } | |
144 | has_dst_ip = 1; | |
145 | } else if (matches(*argv, "id") == 0) { | |
146 | NEXT_ARG(); | |
147 | ret = tunnel_key_parse_key_id(*argv, TCA_TUNNEL_KEY_ENC_KEY_ID, n); | |
148 | if (ret < 0) { | |
149 | fprintf(stderr, "Illegal \"id\"\n"); | |
150 | return -1; | |
151 | } | |
152 | has_key_id = 1; | |
449c709c HHZ |
153 | } else if (matches(*argv, "dst_port") == 0) { |
154 | NEXT_ARG(); | |
155 | ret = tunnel_key_parse_dst_port(*argv, | |
156 | TCA_TUNNEL_KEY_ENC_DST_PORT, n); | |
157 | if (ret < 0) { | |
158 | fprintf(stderr, "Illegal \"dst port\"\n"); | |
159 | return -1; | |
160 | } | |
59eb271d JB |
161 | } else if (matches(*argv, "csum") == 0) { |
162 | csum = 1; | |
163 | } else if (matches(*argv, "nocsum") == 0) { | |
164 | csum = 0; | |
d57639a4 AV |
165 | } else if (matches(*argv, "help") == 0) { |
166 | usage(); | |
167 | } else { | |
168 | break; | |
169 | } | |
170 | NEXT_ARG_FWD(); | |
171 | } | |
172 | ||
59eb271d JB |
173 | addattr8(n, MAX_MSG, TCA_TUNNEL_KEY_NO_CSUM, !csum); |
174 | ||
e67aba55 JP |
175 | parse_action_control_dflt(&argc, &argv, &parm.action, |
176 | false, TC_ACT_PIPE); | |
d57639a4 | 177 | |
3572e01a | 178 | NEXT_ARG_FWD(); |
d57639a4 AV |
179 | if (argc) { |
180 | if (matches(*argv, "index") == 0) { | |
181 | NEXT_ARG(); | |
182 | if (get_u32(&parm.index, *argv, 10)) { | |
183 | fprintf(stderr, "tunnel_key: Illegal \"index\"\n"); | |
184 | return -1; | |
185 | } | |
186 | ||
187 | NEXT_ARG_FWD(); | |
188 | } | |
189 | } | |
190 | ||
191 | if (action == TCA_TUNNEL_KEY_ACT_SET && | |
192 | (!has_src_ip || !has_dst_ip || !has_key_id)) { | |
193 | fprintf(stderr, "set needs tunnel_key parameters\n"); | |
194 | explain(); | |
195 | return -1; | |
196 | } | |
197 | ||
198 | parm.t_action = action; | |
199 | addattr_l(n, MAX_MSG, TCA_TUNNEL_KEY_PARMS, &parm, sizeof(parm)); | |
200 | tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; | |
201 | ||
202 | *argc_p = argc; | |
203 | *argv_p = argv; | |
204 | ||
205 | return 0; | |
206 | } | |
207 | ||
208 | static void tunnel_key_print_ip_addr(FILE *f, const char *name, | |
209 | struct rtattr *attr) | |
210 | { | |
211 | int family; | |
212 | size_t len; | |
213 | ||
214 | if (!attr) | |
215 | return; | |
216 | ||
217 | len = RTA_PAYLOAD(attr); | |
218 | ||
219 | if (len == 4) | |
220 | family = AF_INET; | |
221 | else if (len == 16) | |
222 | family = AF_INET6; | |
223 | else | |
224 | return; | |
225 | ||
226 | fprintf(f, "\n\t%s %s", name, rt_addr_n2a_rta(family, attr)); | |
227 | } | |
228 | ||
229 | static void tunnel_key_print_key_id(FILE *f, const char *name, | |
230 | struct rtattr *attr) | |
231 | { | |
232 | if (!attr) | |
233 | return; | |
234 | fprintf(f, "\n\t%s %d", name, rta_getattr_be32(attr)); | |
235 | } | |
236 | ||
449c709c HHZ |
237 | static void tunnel_key_print_dst_port(FILE *f, char *name, |
238 | struct rtattr *attr) | |
239 | { | |
240 | if (!attr) | |
241 | return; | |
242 | fprintf(f, "\n\t%s %d", name, rta_getattr_be16(attr)); | |
243 | } | |
244 | ||
59eb271d JB |
245 | static void tunnel_key_print_flag(FILE *f, const char *name_on, |
246 | const char *name_off, | |
247 | struct rtattr *attr) | |
248 | { | |
249 | if (!attr) | |
250 | return; | |
251 | fprintf(f, "\n\t%s", rta_getattr_u8(attr) ? name_on : name_off); | |
252 | } | |
253 | ||
d57639a4 AV |
254 | static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg) |
255 | { | |
256 | struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1]; | |
257 | struct tc_tunnel_key *parm; | |
258 | ||
259 | if (!arg) | |
260 | return -1; | |
261 | ||
262 | parse_rtattr_nested(tb, TCA_TUNNEL_KEY_MAX, arg); | |
263 | ||
264 | if (!tb[TCA_TUNNEL_KEY_PARMS]) { | |
265 | fprintf(f, "[NULL tunnel_key parameters]"); | |
266 | return -1; | |
267 | } | |
268 | parm = RTA_DATA(tb[TCA_TUNNEL_KEY_PARMS]); | |
269 | ||
270 | fprintf(f, "tunnel_key"); | |
271 | ||
272 | switch (parm->t_action) { | |
273 | case TCA_TUNNEL_KEY_ACT_RELEASE: | |
274 | fprintf(f, " unset"); | |
275 | break; | |
276 | case TCA_TUNNEL_KEY_ACT_SET: | |
277 | fprintf(f, " set"); | |
278 | tunnel_key_print_ip_addr(f, "src_ip", | |
279 | tb[TCA_TUNNEL_KEY_ENC_IPV4_SRC]); | |
280 | tunnel_key_print_ip_addr(f, "dst_ip", | |
281 | tb[TCA_TUNNEL_KEY_ENC_IPV4_DST]); | |
282 | tunnel_key_print_ip_addr(f, "src_ip", | |
283 | tb[TCA_TUNNEL_KEY_ENC_IPV6_SRC]); | |
284 | tunnel_key_print_ip_addr(f, "dst_ip", | |
285 | tb[TCA_TUNNEL_KEY_ENC_IPV6_DST]); | |
286 | tunnel_key_print_key_id(f, "key_id", | |
287 | tb[TCA_TUNNEL_KEY_ENC_KEY_ID]); | |
449c709c HHZ |
288 | tunnel_key_print_dst_port(f, "dst_port", |
289 | tb[TCA_TUNNEL_KEY_ENC_DST_PORT]); | |
59eb271d JB |
290 | tunnel_key_print_flag(f, "nocsum", "csum", |
291 | tb[TCA_TUNNEL_KEY_NO_CSUM]); | |
d57639a4 AV |
292 | break; |
293 | } | |
e67aba55 | 294 | print_action_control(f, " ", parm->action, ""); |
d57639a4 AV |
295 | |
296 | fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt, | |
297 | parm->bindcnt); | |
298 | ||
299 | if (show_stats) { | |
300 | if (tb[TCA_TUNNEL_KEY_TM]) { | |
301 | struct tcf_t *tm = RTA_DATA(tb[TCA_TUNNEL_KEY_TM]); | |
302 | ||
303 | print_tm(f, tm); | |
304 | } | |
305 | } | |
306 | ||
307 | fprintf(f, "\n "); | |
308 | ||
309 | return 0; | |
310 | } | |
311 | ||
312 | struct action_util tunnel_key_action_util = { | |
313 | .id = "tunnel_key", | |
314 | .parse_aopt = parse_tunnel_key, | |
315 | .print_aopt = print_tunnel_key, | |
316 | }; |