]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iproute_lwtunnel.c
ila: Support for checksum neutral translation
[mirror_iproute2.git] / ip / iproute_lwtunnel.c
1 /*
2 * iproute_lwtunnel.c
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: Roopa Prabhu, <roopa@cumulusnetworks.com>
10 * Thomas Graf <tgraf@suug.ch>
11 *
12 */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <linux/ila.h>
20 #include <linux/lwtunnel.h>
21 #include <linux/mpls_iptunnel.h>
22 #include <errno.h>
23
24 #include "rt_names.h"
25 #include "utils.h"
26 #include "iproute_lwtunnel.h"
27
28 static int read_encap_type(const char *name)
29 {
30 if (strcmp(name, "mpls") == 0)
31 return LWTUNNEL_ENCAP_MPLS;
32 else if (strcmp(name, "ip") == 0)
33 return LWTUNNEL_ENCAP_IP;
34 else if (strcmp(name, "ip6") == 0)
35 return LWTUNNEL_ENCAP_IP6;
36 else if (strcmp(name, "ila") == 0)
37 return LWTUNNEL_ENCAP_ILA;
38 else
39 return LWTUNNEL_ENCAP_NONE;
40 }
41
42 static const char *format_encap_type(int type)
43 {
44 switch (type) {
45 case LWTUNNEL_ENCAP_MPLS:
46 return "mpls";
47 case LWTUNNEL_ENCAP_IP:
48 return "ip";
49 case LWTUNNEL_ENCAP_IP6:
50 return "ip6";
51 case LWTUNNEL_ENCAP_ILA:
52 return "ila";
53 default:
54 return "unknown";
55 }
56 }
57
58 static void print_encap_mpls(FILE *fp, struct rtattr *encap)
59 {
60 struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
61
62 parse_rtattr_nested(tb, MPLS_IPTUNNEL_MAX, encap);
63
64 if (tb[MPLS_IPTUNNEL_DST])
65 fprintf(fp, " %s ",
66 format_host_rta(AF_MPLS, tb[MPLS_IPTUNNEL_DST]));
67 }
68
69 static void print_encap_ip(FILE *fp, struct rtattr *encap)
70 {
71 struct rtattr *tb[LWTUNNEL_IP_MAX+1];
72
73 parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
74
75 if (tb[LWTUNNEL_IP_ID])
76 fprintf(fp, "id %llu ", ntohll(rta_getattr_u64(tb[LWTUNNEL_IP_ID])));
77
78 if (tb[LWTUNNEL_IP_SRC])
79 fprintf(fp, "src %s ",
80 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_SRC]));
81
82 if (tb[LWTUNNEL_IP_DST])
83 fprintf(fp, "dst %s ",
84 rt_addr_n2a_rta(AF_INET, tb[LWTUNNEL_IP_DST]));
85
86 if (tb[LWTUNNEL_IP_TTL])
87 fprintf(fp, "ttl %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TTL]));
88
89 if (tb[LWTUNNEL_IP_TOS])
90 fprintf(fp, "tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
91 }
92
93 static char *ila_csum_mode2name(__u8 csum_mode)
94 {
95 switch (csum_mode) {
96 case ILA_CSUM_ADJUST_TRANSPORT:
97 return "adj-transport";
98 case ILA_CSUM_NEUTRAL_MAP:
99 return "neutral-map";
100 case ILA_CSUM_NO_ACTION:
101 return "no-action";
102 default:
103 return "unknown";
104 }
105 }
106
107 static __u8 ila_csum_name2mode(char *name)
108 {
109 if (strcmp(name, "adj-transport") == 0)
110 return ILA_CSUM_ADJUST_TRANSPORT;
111 else if (strcmp(name, "neutral-map") == 0)
112 return ILA_CSUM_NEUTRAL_MAP;
113 else if (strcmp(name, "no-action") == 0)
114 return ILA_CSUM_NO_ACTION;
115 else
116 return -1;
117 }
118
119 static void print_encap_ila(FILE *fp, struct rtattr *encap)
120 {
121 struct rtattr *tb[ILA_ATTR_MAX+1];
122
123 parse_rtattr_nested(tb, ILA_ATTR_MAX, encap);
124
125 if (tb[ILA_ATTR_LOCATOR]) {
126 char abuf[ADDR64_BUF_SIZE];
127
128 addr64_n2a(*(__u64 *)RTA_DATA(tb[ILA_ATTR_LOCATOR]),
129 abuf, sizeof(abuf));
130 fprintf(fp, " %s ", abuf);
131 }
132
133 if (tb[ILA_ATTR_CSUM_MODE])
134 fprintf(fp, " csum-mode %s ",
135 ila_csum_mode2name(rta_getattr_u8(tb[ILA_ATTR_CSUM_MODE])));
136 }
137
138 static void print_encap_ip6(FILE *fp, struct rtattr *encap)
139 {
140 struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
141
142 parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
143
144 if (tb[LWTUNNEL_IP6_ID])
145 fprintf(fp, "id %llu ", ntohll(rta_getattr_u64(tb[LWTUNNEL_IP6_ID])));
146
147 if (tb[LWTUNNEL_IP6_SRC])
148 fprintf(fp, "src %s ",
149 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_SRC]));
150
151 if (tb[LWTUNNEL_IP6_DST])
152 fprintf(fp, "dst %s ",
153 rt_addr_n2a_rta(AF_INET6, tb[LWTUNNEL_IP6_DST]));
154
155 if (tb[LWTUNNEL_IP6_HOPLIMIT])
156 fprintf(fp, "hoplimit %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_HOPLIMIT]));
157
158 if (tb[LWTUNNEL_IP6_TC])
159 fprintf(fp, "tc %d ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
160 }
161
162 void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
163 struct rtattr *encap)
164 {
165 int et;
166
167 if (!encap_type)
168 return;
169
170 et = rta_getattr_u16(encap_type);
171
172 fprintf(fp, " encap %s ", format_encap_type(et));
173
174 switch (et) {
175 case LWTUNNEL_ENCAP_MPLS:
176 print_encap_mpls(fp, encap);
177 break;
178 case LWTUNNEL_ENCAP_IP:
179 print_encap_ip(fp, encap);
180 break;
181 case LWTUNNEL_ENCAP_ILA:
182 print_encap_ila(fp, encap);
183 break;
184 case LWTUNNEL_ENCAP_IP6:
185 print_encap_ip6(fp, encap);
186 break;
187 }
188 }
189
190 static int parse_encap_mpls(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
191 {
192 inet_prefix addr;
193 int argc = *argcp;
194 char **argv = *argvp;
195
196 if (get_addr(&addr, *argv, AF_MPLS)) {
197 fprintf(stderr, "Error: an inet address is expected rather than \"%s\".\n", *argv);
198 exit(1);
199 }
200
201 rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
202 addr.bytelen);
203
204 *argcp = argc;
205 *argvp = argv;
206
207 return 0;
208 }
209
210 static int parse_encap_ip(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
211 {
212 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
213 char **argv = *argvp;
214 int argc = *argcp;
215
216 while (argc > 0) {
217 if (strcmp(*argv, "id") == 0) {
218 __u64 id;
219
220 NEXT_ARG();
221 if (id_ok++)
222 duparg2("id", *argv);
223 if (get_be64(&id, *argv, 0))
224 invarg("\"id\" value is invalid\n", *argv);
225 rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
226 } else if (strcmp(*argv, "dst") == 0) {
227 inet_prefix addr;
228
229 NEXT_ARG();
230 if (dst_ok++)
231 duparg2("dst", *argv);
232 get_addr(&addr, *argv, AF_INET);
233 rta_addattr_l(rta, len, LWTUNNEL_IP_DST, &addr.data, addr.bytelen);
234 } else if (strcmp(*argv, "tos") == 0) {
235 __u32 tos;
236
237 NEXT_ARG();
238 if (tos_ok++)
239 duparg2("tos", *argv);
240 if (rtnl_dsfield_a2n(&tos, *argv))
241 invarg("\"tos\" value is invalid\n", *argv);
242 rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
243 } else if (strcmp(*argv, "ttl") == 0) {
244 __u8 ttl;
245
246 NEXT_ARG();
247 if (ttl_ok++)
248 duparg2("ttl", *argv);
249 if (get_u8(&ttl, *argv, 0))
250 invarg("\"ttl\" value is invalid\n", *argv);
251 rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
252 } else {
253 break;
254 }
255 argc--; argv++;
256 }
257
258 /* argv is currently the first unparsed argument,
259 * but the lwt_parse_encap() caller will move to the next,
260 * so step back */
261 *argcp = argc + 1;
262 *argvp = argv - 1;
263
264 return 0;
265 }
266
267 static int parse_encap_ila(struct rtattr *rta, size_t len,
268 int *argcp, char ***argvp)
269 {
270 __u64 locator;
271 int argc = *argcp;
272 char **argv = *argvp;
273
274 if (get_addr64(&locator, *argv) < 0) {
275 fprintf(stderr, "Bad locator: %s\n", *argv);
276 exit(1);
277 }
278
279 argc--; argv++;
280
281 rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
282
283 while (argc > 0) {
284 if (strcmp(*argv, "csum-mode") == 0) {
285 __u8 csum_mode;
286
287 NEXT_ARG();
288
289 csum_mode = ila_csum_name2mode(*argv);
290 if (csum_mode < 0)
291 invarg("\"csum-mode\" value is invalid\n", *argv);
292
293 rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE, csum_mode);
294
295 argc--; argv++;
296 } else {
297 break;
298 }
299 }
300
301 /* argv is currently the first unparsed argument,
302 * but the lwt_parse_encap() caller will move to the next,
303 * so step back
304 */
305 *argcp = argc + 1;
306 *argvp = argv - 1;
307
308 return 0;
309 }
310
311 static int parse_encap_ip6(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
312 {
313 int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
314 char **argv = *argvp;
315 int argc = *argcp;
316
317 while (argc > 0) {
318 if (strcmp(*argv, "id") == 0) {
319 __u64 id;
320
321 NEXT_ARG();
322 if (id_ok++)
323 duparg2("id", *argv);
324 if (get_be64(&id, *argv, 0))
325 invarg("\"id\" value is invalid\n", *argv);
326 rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
327 } else if (strcmp(*argv, "dst") == 0) {
328 inet_prefix addr;
329
330 NEXT_ARG();
331 if (dst_ok++)
332 duparg2("dst", *argv);
333 get_addr(&addr, *argv, AF_INET6);
334 rta_addattr_l(rta, len, LWTUNNEL_IP6_DST, &addr.data, addr.bytelen);
335 } else if (strcmp(*argv, "tc") == 0) {
336 __u32 tc;
337
338 NEXT_ARG();
339 if (tos_ok++)
340 duparg2("tc", *argv);
341 if (rtnl_dsfield_a2n(&tc, *argv))
342 invarg("\"tc\" value is invalid\n", *argv);
343 rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
344 } else if (strcmp(*argv, "hoplimit") == 0) {
345 __u8 hoplimit;
346
347 NEXT_ARG();
348 if (ttl_ok++)
349 duparg2("hoplimit", *argv);
350 if (get_u8(&hoplimit, *argv, 0))
351 invarg("\"hoplimit\" value is invalid\n", *argv);
352 rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
353 } else {
354 break;
355 }
356 argc--; argv++;
357 }
358
359 /* argv is currently the first unparsed argument,
360 * but the lwt_parse_encap() caller will move to the next,
361 * so step back */
362 *argcp = argc + 1;
363 *argvp = argv - 1;
364
365 return 0;
366 }
367
368 int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
369 {
370 struct rtattr *nest;
371 int argc = *argcp;
372 char **argv = *argvp;
373 __u16 type;
374
375 NEXT_ARG();
376 type = read_encap_type(*argv);
377 if (!type)
378 invarg("\"encap type\" value is invalid\n", *argv);
379
380 NEXT_ARG();
381 if (argc <= 1) {
382 fprintf(stderr, "Error: unexpected end of line after \"encap\"\n");
383 exit(-1);
384 }
385
386 nest = rta_nest(rta, 1024, RTA_ENCAP);
387 switch (type) {
388 case LWTUNNEL_ENCAP_MPLS:
389 parse_encap_mpls(rta, len, &argc, &argv);
390 break;
391 case LWTUNNEL_ENCAP_IP:
392 parse_encap_ip(rta, len, &argc, &argv);
393 break;
394 case LWTUNNEL_ENCAP_ILA:
395 parse_encap_ila(rta, len, &argc, &argv);
396 break;
397 case LWTUNNEL_ENCAP_IP6:
398 parse_encap_ip6(rta, len, &argc, &argv);
399 break;
400 default:
401 fprintf(stderr, "Error: unsupported encap type\n");
402 break;
403 }
404 rta_nest_end(rta, nest);
405
406 rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
407
408 *argcp = argc;
409 *argvp = argv;
410
411 return 0;
412 }