]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/link_ip6tnl.c
iproute: Set ip/ip6 lwtunnel flags
[mirror_iproute2.git] / ip / link_ip6tnl.c
1 /*
2 * link_ip6tnl.c ip6tnl driver 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: Nicolas Dichtel <nicolas.dichtel@6wind.com>
10 *
11 */
12
13 #include <string.h>
14 #include <net/if.h>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
18
19 #include <linux/ip.h>
20 #include <linux/if_tunnel.h>
21 #include <linux/ip6_tunnel.h>
22 #include "rt_names.h"
23 #include "utils.h"
24 #include "ip_common.h"
25 #include "tunnel.h"
26
27 #define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
28 #define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
29
30 #define DEFAULT_TNL_HOP_LIMIT (64)
31
32 static void ip6tunnel_print_help(struct link_util *lu, int argc, char **argv,
33 FILE *f)
34 {
35 const char *mode;
36
37 fprintf(f,
38 "Usage: ... %-6s [ remote ADDR ]\n",
39 lu->id
40 );
41 fprintf(f,
42 " [ local ADDR ]\n"
43 " [ encaplimit ELIM ]\n"
44 " [ hoplimit HLIM ]\n"
45 " [ tclass TCLASS ]\n"
46 " [ flowlabel FLOWLABEL ]\n"
47 " [ dscp inherit ]\n"
48 " [ [no]allow-localremote ]\n"
49 " [ dev PHYS_DEV ]\n"
50 " [ fwmark MARK ]\n"
51 " [ external ]\n"
52 " [ noencap ]\n"
53 " [ encap { fou | gue | none } ]\n"
54 " [ encap-sport PORT ]\n"
55 " [ encap-dport PORT ]\n"
56 " [ [no]encap-csum ]\n"
57 " [ [no]encap-csum6 ]\n"
58 " [ [no]encap-remcsum ]\n"
59 );
60 mode = "{ ip6ip6 | ipip6 | any }";
61 fprintf(f,
62 " [ mode %s ]\n"
63 "\n",
64 mode
65 );
66 fprintf(f,
67 "Where: ADDR := IPV6_ADDRESS\n"
68 " ELIM := { none | 0..255 }(default=%d)\n"
69 " HLIM := 0..255 (default=%d)\n"
70 " TCLASS := { 0x0..0xff | inherit }\n"
71 " FLOWLABEL := { 0x0..0xfffff | inherit }\n"
72 " MARK := { 0x0..0xffffffff | inherit }\n",
73 IPV6_DEFAULT_TNL_ENCAP_LIMIT, DEFAULT_TNL_HOP_LIMIT
74 );
75 }
76
77 static int ip6tunnel_parse_opt(struct link_util *lu, int argc, char **argv,
78 struct nlmsghdr *n)
79 {
80 struct ifinfomsg *ifi = NLMSG_DATA(n);
81 struct {
82 struct nlmsghdr n;
83 struct ifinfomsg i;
84 } req = {
85 .n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
86 .n.nlmsg_flags = NLM_F_REQUEST,
87 .n.nlmsg_type = RTM_GETLINK,
88 .i.ifi_family = preferred_family,
89 .i.ifi_index = ifi->ifi_index,
90 };
91 struct nlmsghdr *answer;
92 struct rtattr *tb[IFLA_MAX + 1];
93 struct rtattr *linkinfo[IFLA_INFO_MAX+1];
94 struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
95 int len;
96 inet_prefix saddr, daddr;
97 __u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
98 __u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
99 __u32 flowinfo = 0;
100 __u32 flags = 0;
101 __u8 proto = 0;
102 __u32 link = 0;
103 __u16 encaptype = 0;
104 __u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
105 __u16 encapsport = 0;
106 __u16 encapdport = 0;
107 __u8 metadata = 0;
108 __u32 fwmark = 0;
109
110 inet_prefix_reset(&saddr);
111 inet_prefix_reset(&daddr);
112
113 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
114 const struct rtattr *rta;
115
116 if (rtnl_talk(&rth, &req.n, &answer) < 0) {
117 get_failed:
118 fprintf(stderr,
119 "Failed to get existing tunnel info.\n");
120 return -1;
121 }
122
123 len = answer->nlmsg_len;
124 len -= NLMSG_LENGTH(sizeof(*ifi));
125 if (len < 0)
126 goto get_failed;
127
128 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), len);
129
130 if (!tb[IFLA_LINKINFO])
131 goto get_failed;
132
133 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
134
135 if (!linkinfo[IFLA_INFO_DATA])
136 goto get_failed;
137
138 parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
139 linkinfo[IFLA_INFO_DATA]);
140
141 rta = iptuninfo[IFLA_IPTUN_LOCAL];
142 if (rta && get_addr_rta(&saddr, rta, AF_INET6))
143 goto get_failed;
144
145 rta = iptuninfo[IFLA_IPTUN_REMOTE];
146 if (rta && get_addr_rta(&daddr, rta, AF_INET6))
147 goto get_failed;
148
149 if (iptuninfo[IFLA_IPTUN_TTL])
150 hop_limit = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);
151
152 if (iptuninfo[IFLA_IPTUN_ENCAP_LIMIT])
153 encap_limit = rta_getattr_u8(iptuninfo[IFLA_IPTUN_ENCAP_LIMIT]);
154
155 if (iptuninfo[IFLA_IPTUN_FLOWINFO])
156 flowinfo = rta_getattr_u32(iptuninfo[IFLA_IPTUN_FLOWINFO]);
157
158 if (iptuninfo[IFLA_IPTUN_FLAGS])
159 flags = rta_getattr_u32(iptuninfo[IFLA_IPTUN_FLAGS]);
160
161 if (iptuninfo[IFLA_IPTUN_LINK])
162 link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]);
163
164 if (iptuninfo[IFLA_IPTUN_PROTO])
165 proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]);
166 if (iptuninfo[IFLA_IPTUN_COLLECT_METADATA])
167 metadata = 1;
168
169 if (iptuninfo[IFLA_IPTUN_FWMARK])
170 fwmark = rta_getattr_u32(iptuninfo[IFLA_IPTUN_FWMARK]);
171
172 free(answer);
173 }
174
175 while (argc > 0) {
176 if (strcmp(*argv, "mode") == 0) {
177 NEXT_ARG();
178 if (strcmp(*argv, "ipv6/ipv6") == 0 ||
179 strcmp(*argv, "ip6ip6") == 0)
180 proto = IPPROTO_IPV6;
181 else if (strcmp(*argv, "ip/ipv6") == 0 ||
182 strcmp(*argv, "ipv4/ipv6") == 0 ||
183 strcmp(*argv, "ipip6") == 0 ||
184 strcmp(*argv, "ip4ip6") == 0)
185 proto = IPPROTO_IPIP;
186 else if (strcmp(*argv, "any/ipv6") == 0 ||
187 strcmp(*argv, "any") == 0)
188 proto = 0;
189 else
190 invarg("Cannot guess tunnel mode.", *argv);
191 } else if (strcmp(*argv, "remote") == 0) {
192 NEXT_ARG();
193 get_addr(&daddr, *argv, AF_INET6);
194 } else if (strcmp(*argv, "local") == 0) {
195 NEXT_ARG();
196 get_addr(&saddr, *argv, AF_INET6);
197 } else if (matches(*argv, "dev") == 0) {
198 NEXT_ARG();
199 link = ll_name_to_index(*argv);
200 if (!link)
201 exit(nodev(*argv));
202 } else if (strcmp(*argv, "ttl") == 0 ||
203 strcmp(*argv, "hoplimit") == 0 ||
204 strcmp(*argv, "hlim") == 0) {
205 NEXT_ARG();
206 if (strcmp(*argv, "inherit") != 0) {
207 if (get_u8(&hop_limit, *argv, 0))
208 invarg("invalid HLIM\n", *argv);
209 } else
210 hop_limit = 0;
211 } else if (strcmp(*argv, "encaplimit") == 0) {
212 NEXT_ARG();
213 if (strcmp(*argv, "none") == 0) {
214 flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
215 } else {
216 __u8 uval;
217
218 if (get_u8(&uval, *argv, 0) < -1)
219 invarg("invalid ELIM", *argv);
220 encap_limit = uval;
221 flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
222 }
223 } else if (strcmp(*argv, "tos") == 0 ||
224 strcmp(*argv, "tclass") == 0 ||
225 strcmp(*argv, "tc") == 0 ||
226 matches(*argv, "dsfield") == 0) {
227 __u8 uval;
228
229 NEXT_ARG();
230 flowinfo &= ~IP6_FLOWINFO_TCLASS;
231 if (strcmp(*argv, "inherit") == 0)
232 flags |= IP6_TNL_F_USE_ORIG_TCLASS;
233 else {
234 if (get_u8(&uval, *argv, 16))
235 invarg("invalid TClass", *argv);
236 flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
237 flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
238 }
239 } else if (strcmp(*argv, "flowlabel") == 0 ||
240 strcmp(*argv, "fl") == 0) {
241 __u32 uval;
242
243 NEXT_ARG();
244 flowinfo &= ~IP6_FLOWINFO_FLOWLABEL;
245 if (strcmp(*argv, "inherit") == 0)
246 flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
247 else {
248 if (get_u32(&uval, *argv, 16))
249 invarg("invalid Flowlabel", *argv);
250 if (uval > 0xFFFFF)
251 invarg("invalid Flowlabel", *argv);
252 flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
253 flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
254 }
255 } else if (strcmp(*argv, "dscp") == 0) {
256 NEXT_ARG();
257 if (strcmp(*argv, "inherit") != 0)
258 invarg("not inherit", *argv);
259 flags |= IP6_TNL_F_RCV_DSCP_COPY;
260 } else if (strcmp(*argv, "fwmark") == 0) {
261 NEXT_ARG();
262 if (strcmp(*argv, "inherit") == 0) {
263 flags |= IP6_TNL_F_USE_ORIG_FWMARK;
264 fwmark = 0;
265 } else {
266 if (get_u32(&fwmark, *argv, 0))
267 invarg("invalid fwmark\n", *argv);
268 flags &= ~IP6_TNL_F_USE_ORIG_FWMARK;
269 }
270 } else if (strcmp(*argv, "allow-localremote") == 0) {
271 flags |= IP6_TNL_F_ALLOW_LOCAL_REMOTE;
272 } else if (strcmp(*argv, "noallow-localremote") == 0) {
273 flags &= ~IP6_TNL_F_ALLOW_LOCAL_REMOTE;
274 } else if (strcmp(*argv, "noencap") == 0) {
275 encaptype = TUNNEL_ENCAP_NONE;
276 } else if (strcmp(*argv, "encap") == 0) {
277 NEXT_ARG();
278 if (strcmp(*argv, "fou") == 0)
279 encaptype = TUNNEL_ENCAP_FOU;
280 else if (strcmp(*argv, "gue") == 0)
281 encaptype = TUNNEL_ENCAP_GUE;
282 else if (strcmp(*argv, "none") == 0)
283 encaptype = TUNNEL_ENCAP_NONE;
284 else
285 invarg("Invalid encap type.", *argv);
286 } else if (strcmp(*argv, "encap-sport") == 0) {
287 NEXT_ARG();
288 if (strcmp(*argv, "auto") == 0)
289 encapsport = 0;
290 else if (get_u16(&encapsport, *argv, 0))
291 invarg("Invalid source port.", *argv);
292 } else if (strcmp(*argv, "encap-dport") == 0) {
293 NEXT_ARG();
294 if (get_u16(&encapdport, *argv, 0))
295 invarg("Invalid destination port.", *argv);
296 } else if (strcmp(*argv, "encap-csum") == 0) {
297 encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
298 } else if (strcmp(*argv, "noencap-csum") == 0) {
299 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
300 } else if (strcmp(*argv, "encap-udp6-csum") == 0) {
301 encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
302 } else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
303 encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM6;
304 } else if (strcmp(*argv, "encap-remcsum") == 0) {
305 encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
306 } else if (strcmp(*argv, "noencap-remcsum") == 0) {
307 encapflags &= ~TUNNEL_ENCAP_FLAG_REMCSUM;
308 } else if (strcmp(*argv, "external") == 0) {
309 metadata = 1;
310 } else {
311 ip6tunnel_print_help(lu, argc, argv, stderr);
312 return -1;
313 }
314 argc--, argv++;
315 }
316
317 addattr8(n, 1024, IFLA_IPTUN_PROTO, proto);
318 if (metadata) {
319 addattr_l(n, 1024, IFLA_IPTUN_COLLECT_METADATA, NULL, 0);
320 return 0;
321 }
322
323 if (is_addrtype_inet_not_unspec(&saddr)) {
324 addattr_l(n, 1024, IFLA_IPTUN_LOCAL,
325 saddr.data, saddr.bytelen);
326 }
327 if (is_addrtype_inet_not_unspec(&daddr)) {
328 addattr_l(n, 1024, IFLA_IPTUN_REMOTE,
329 daddr.data, daddr.bytelen);
330 }
331 addattr8(n, 1024, IFLA_IPTUN_TTL, hop_limit);
332 addattr8(n, 1024, IFLA_IPTUN_ENCAP_LIMIT, encap_limit);
333 addattr32(n, 1024, IFLA_IPTUN_FLOWINFO, flowinfo);
334 addattr32(n, 1024, IFLA_IPTUN_FLAGS, flags);
335 addattr32(n, 1024, IFLA_IPTUN_LINK, link);
336 addattr32(n, 1024, IFLA_IPTUN_FWMARK, fwmark);
337
338 addattr16(n, 1024, IFLA_IPTUN_ENCAP_TYPE, encaptype);
339 addattr16(n, 1024, IFLA_IPTUN_ENCAP_FLAGS, encapflags);
340 addattr16(n, 1024, IFLA_IPTUN_ENCAP_SPORT, htons(encapsport));
341 addattr16(n, 1024, IFLA_IPTUN_ENCAP_DPORT, htons(encapdport));
342
343 return 0;
344 }
345
346 static void ip6tunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
347 {
348 char s2[64];
349 __u32 flags = 0;
350 __u32 flowinfo = 0;
351 __u8 ttl = 0;
352
353 if (!tb)
354 return;
355
356 if (tb[IFLA_IPTUN_COLLECT_METADATA]) {
357 print_bool(PRINT_ANY, "external", "external", true);
358 return;
359 }
360
361 if (tb[IFLA_IPTUN_FLAGS])
362 flags = rta_getattr_u32(tb[IFLA_IPTUN_FLAGS]);
363
364 if (tb[IFLA_IPTUN_FLOWINFO])
365 flowinfo = rta_getattr_u32(tb[IFLA_IPTUN_FLOWINFO]);
366
367 if (tb[IFLA_IPTUN_PROTO]) {
368 switch (rta_getattr_u8(tb[IFLA_IPTUN_PROTO])) {
369 case IPPROTO_IPIP:
370 print_string(PRINT_ANY, "proto", "%s ", "ipip6");
371 break;
372 case IPPROTO_IPV6:
373 print_string(PRINT_ANY, "proto", "%s ", "ip6ip6");
374 break;
375 case 0:
376 print_string(PRINT_ANY, "proto", "%s ", "any");
377 break;
378 }
379 }
380
381 tnl_print_endpoint("remote", tb[IFLA_IPTUN_REMOTE], AF_INET6);
382 tnl_print_endpoint("local", tb[IFLA_IPTUN_LOCAL], AF_INET6);
383
384 if (tb[IFLA_IPTUN_LINK]) {
385 __u32 link = rta_getattr_u32(tb[IFLA_IPTUN_LINK]);
386
387 if (link) {
388 print_string(PRINT_ANY, "link", "dev %s ",
389 ll_index_to_name(link));
390 }
391 }
392
393 if (tb[IFLA_IPTUN_TTL])
394 ttl = rta_getattr_u8(tb[IFLA_IPTUN_TTL]);
395 if (is_json_context() || ttl)
396 print_uint(PRINT_ANY, "ttl", "hoplimit %u ", ttl);
397 else
398 print_string(PRINT_FP, NULL, "hoplimit %s ", "inherit");
399
400 if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT) {
401 print_bool(PRINT_ANY,
402 "ip6_tnl_f_ign_encap_limit",
403 "encaplimit none ",
404 true);
405 } else if (tb[IFLA_IPTUN_ENCAP_LIMIT]) {
406 __u8 val = rta_getattr_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]);
407
408 print_uint(PRINT_ANY, "encap_limit", "encaplimit %u ", val);
409 }
410
411 if (flags & IP6_TNL_F_USE_ORIG_TCLASS) {
412 print_bool(PRINT_ANY,
413 "ip6_tnl_f_use_orig_tclass",
414 "tclass inherit ",
415 true);
416 } else if (tb[IFLA_IPTUN_FLOWINFO]) {
417 __u32 val = ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20;
418
419 snprintf(s2, sizeof(s2), "0x%02x", val);
420 print_string(PRINT_ANY, "tclass", "tclass %s ", s2);
421 }
422
423 if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) {
424 print_bool(PRINT_ANY,
425 "ip6_tnl_f_use_orig_flowlabel",
426 "flowlabel inherit ",
427 true);
428 } else if (tb[IFLA_IPTUN_FLOWINFO]) {
429 __u32 val = ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL);
430
431 snprintf(s2, sizeof(s2), "0x%05x", val);
432 print_string(PRINT_ANY, "flowlabel", "flowlabel %s ", s2);
433 }
434
435 if (flags & IP6_TNL_F_RCV_DSCP_COPY)
436 print_bool(PRINT_ANY,
437 "ip6_tnl_f_rcv_dscp_copy",
438 "dscp inherit ",
439 true);
440
441 if (flags & IP6_TNL_F_MIP6_DEV)
442 print_bool(PRINT_ANY, "ip6_tnl_f_mip6_dev", "mip6 ", true);
443
444 if (flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE)
445 print_bool(PRINT_ANY,
446 "ip6_tnl_f_allow_local_remote",
447 "allow-localremote ",
448 true);
449
450 if (flags & IP6_TNL_F_USE_ORIG_FWMARK) {
451 print_bool(PRINT_ANY,
452 "ip6_tnl_f_use_orig_fwmark",
453 "fwmark inherit ",
454 true);
455 } else if (tb[IFLA_IPTUN_FWMARK]) {
456 __u32 fwmark = rta_getattr_u32(tb[IFLA_IPTUN_FWMARK]);
457
458 if (fwmark) {
459 print_0xhex(PRINT_ANY,
460 "fwmark", "fwmark %#llx ", fwmark);
461 }
462 }
463
464 tnl_print_encap(tb,
465 IFLA_IPTUN_ENCAP_TYPE,
466 IFLA_IPTUN_ENCAP_FLAGS,
467 IFLA_IPTUN_ENCAP_SPORT,
468 IFLA_IPTUN_ENCAP_DPORT);
469 }
470
471 struct link_util ip6tnl_link_util = {
472 .id = "ip6tnl",
473 .maxattr = IFLA_IPTUN_MAX,
474 .parse_opt = ip6tunnel_parse_opt,
475 .print_opt = ip6tunnel_print_opt,
476 .print_help = ip6tunnel_print_help,
477 };