2 * link_gre6.c gre driver module
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.
9 * Authors: Dmitry Kozlov <xeb@mail.ru>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
20 #include <linux/if_tunnel.h>
21 #include <linux/ip6_tunnel.h>
25 #include "ip_common.h"
28 #define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
29 #define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
31 #define DEFAULT_TNL_HOP_LIMIT (64)
33 static void print_usage(FILE *f
)
36 "Usage: ... { ip6gre | ip6gretap } [ remote ADDR ]\n"
42 " [ encaplimit ELIM ]\n"
43 " [ tclass TCLASS ]\n"
44 " [ flowlabel FLOWLABEL ]\n"
49 " [ encap { fou | gue | none } ]\n"
50 " [ encap-sport PORT ]\n"
51 " [ encap-dport PORT ]\n"
52 " [ [no]encap-csum ]\n"
53 " [ [no]encap-csum6 ]\n"
54 " [ [no]encap-remcsum ]\n"
56 "Where: ADDR := IPV6_ADDRESS\n"
57 " TTL := { 0..255 } (default=%d)\n"
58 " KEY := { DOTTED_QUAD | NUMBER }\n"
59 " ELIM := { none | 0..255 }(default=%d)\n"
60 " TCLASS := { 0x0..0xff | inherit }\n"
61 " FLOWLABEL := { 0x0..0xfffff | inherit }\n"
62 " MARK := { 0x0..0xffffffff | inherit }\n",
63 DEFAULT_TNL_HOP_LIMIT
, IPV6_DEFAULT_TNL_ENCAP_LIMIT
67 static void usage(void) __attribute__((noreturn
));
68 static void usage(void)
74 static int gre_parse_opt(struct link_util
*lu
, int argc
, char **argv
,
77 struct ifinfomsg
*ifi
= (struct ifinfomsg
*)(n
+ 1);
83 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(*ifi
)),
84 .n
.nlmsg_flags
= NLM_F_REQUEST
,
85 .n
.nlmsg_type
= RTM_GETLINK
,
86 .i
.ifi_family
= preferred_family
,
87 .i
.ifi_index
= ifi
->ifi_index
,
89 struct rtattr
*tb
[IFLA_MAX
+ 1];
90 struct rtattr
*linkinfo
[IFLA_INFO_MAX
+1];
91 struct rtattr
*greinfo
[IFLA_GRE_MAX
+ 1];
94 unsigned int ikey
= 0;
95 unsigned int okey
= 0;
96 struct in6_addr raddr
= IN6ADDR_ANY_INIT
;
97 struct in6_addr laddr
= IN6ADDR_ANY_INIT
;
98 unsigned int link
= 0;
99 unsigned int flowinfo
= 0;
100 unsigned int flags
= 0;
101 __u8 hop_limit
= DEFAULT_TNL_HOP_LIMIT
;
102 __u8 encap_limit
= IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
104 __u16 encapflags
= TUNNEL_ENCAP_FLAG_CSUM6
;
105 __u16 encapsport
= 0;
106 __u16 encapdport
= 0;
110 if (!(n
->nlmsg_flags
& NLM_F_CREATE
)) {
111 if (rtnl_talk(&rth
, &req
.n
, &req
.n
, sizeof(req
)) < 0) {
114 "Failed to get existing tunnel info.\n");
118 len
= req
.n
.nlmsg_len
;
119 len
-= NLMSG_LENGTH(sizeof(*ifi
));
123 parse_rtattr(tb
, IFLA_MAX
, IFLA_RTA(&req
.i
), len
);
125 if (!tb
[IFLA_LINKINFO
])
128 parse_rtattr_nested(linkinfo
, IFLA_INFO_MAX
, tb
[IFLA_LINKINFO
]);
130 if (!linkinfo
[IFLA_INFO_DATA
])
133 parse_rtattr_nested(greinfo
, IFLA_GRE_MAX
,
134 linkinfo
[IFLA_INFO_DATA
]);
136 if (greinfo
[IFLA_GRE_IKEY
])
137 ikey
= rta_getattr_u32(greinfo
[IFLA_GRE_IKEY
]);
139 if (greinfo
[IFLA_GRE_OKEY
])
140 okey
= rta_getattr_u32(greinfo
[IFLA_GRE_OKEY
]);
142 if (greinfo
[IFLA_GRE_IFLAGS
])
143 iflags
= rta_getattr_u16(greinfo
[IFLA_GRE_IFLAGS
]);
145 if (greinfo
[IFLA_GRE_OFLAGS
])
146 oflags
= rta_getattr_u16(greinfo
[IFLA_GRE_OFLAGS
]);
148 if (greinfo
[IFLA_GRE_LOCAL
])
149 memcpy(&laddr
, RTA_DATA(greinfo
[IFLA_GRE_LOCAL
]), sizeof(laddr
));
151 if (greinfo
[IFLA_GRE_REMOTE
])
152 memcpy(&raddr
, RTA_DATA(greinfo
[IFLA_GRE_REMOTE
]), sizeof(raddr
));
154 if (greinfo
[IFLA_GRE_TTL
])
155 hop_limit
= rta_getattr_u8(greinfo
[IFLA_GRE_TTL
]);
157 if (greinfo
[IFLA_GRE_LINK
])
158 link
= rta_getattr_u32(greinfo
[IFLA_GRE_LINK
]);
160 if (greinfo
[IFLA_GRE_ENCAP_LIMIT
])
161 encap_limit
= rta_getattr_u8(greinfo
[IFLA_GRE_ENCAP_LIMIT
]);
163 if (greinfo
[IFLA_GRE_FLOWINFO
])
164 flowinfo
= rta_getattr_u32(greinfo
[IFLA_GRE_FLOWINFO
]);
166 if (greinfo
[IFLA_GRE_FLAGS
])
167 flags
= rta_getattr_u32(greinfo
[IFLA_GRE_FLAGS
]);
169 if (greinfo
[IFLA_GRE_ENCAP_TYPE
])
170 encaptype
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_TYPE
]);
172 if (greinfo
[IFLA_GRE_ENCAP_FLAGS
])
173 encapflags
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_FLAGS
]);
175 if (greinfo
[IFLA_GRE_ENCAP_SPORT
])
176 encapsport
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_SPORT
]);
178 if (greinfo
[IFLA_GRE_ENCAP_DPORT
])
179 encapdport
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_DPORT
]);
181 if (greinfo
[IFLA_GRE_FWMARK
])
182 fwmark
= rta_getattr_u32(greinfo
[IFLA_GRE_FWMARK
]);
186 if (!matches(*argv
, "key")) {
192 if (strchr(*argv
, '.'))
193 uval
= get_addr32(*argv
);
195 if (get_unsigned(&uval
, *argv
, 0) < 0) {
197 "Invalid value for \"key\"\n");
204 } else if (!matches(*argv
, "ikey")) {
209 if (strchr(*argv
, '.'))
210 uval
= get_addr32(*argv
);
212 if (get_unsigned(&uval
, *argv
, 0) < 0) {
213 fprintf(stderr
, "invalid value of \"ikey\"\n");
219 } else if (!matches(*argv
, "okey")) {
224 if (strchr(*argv
, '.'))
225 uval
= get_addr32(*argv
);
227 if (get_unsigned(&uval
, *argv
, 0) < 0) {
228 fprintf(stderr
, "invalid value of \"okey\"\n");
234 } else if (!matches(*argv
, "seq")) {
237 } else if (!matches(*argv
, "iseq")) {
239 } else if (!matches(*argv
, "oseq")) {
241 } else if (!matches(*argv
, "csum")) {
244 } else if (!matches(*argv
, "icsum")) {
246 } else if (!matches(*argv
, "ocsum")) {
248 } else if (!matches(*argv
, "remote")) {
252 get_prefix(&addr
, *argv
, preferred_family
);
253 if (addr
.family
== AF_UNSPEC
)
254 invarg("\"remote\" address family is AF_UNSPEC", *argv
);
255 memcpy(&raddr
, &addr
.data
, sizeof(raddr
));
256 } else if (!matches(*argv
, "local")) {
260 get_prefix(&addr
, *argv
, preferred_family
);
261 if (addr
.family
== AF_UNSPEC
)
262 invarg("\"local\" address family is AF_UNSPEC", *argv
);
263 memcpy(&laddr
, &addr
.data
, sizeof(laddr
));
264 } else if (!matches(*argv
, "dev")) {
266 link
= if_nametoindex(*argv
);
268 fprintf(stderr
, "Cannot find device \"%s\"\n",
272 } else if (!matches(*argv
, "ttl") ||
273 !matches(*argv
, "hoplimit")) {
277 if (get_u8(&uval
, *argv
, 0))
278 invarg("invalid TTL", *argv
);
280 } else if (!matches(*argv
, "tos") ||
281 !matches(*argv
, "tclass") ||
282 !matches(*argv
, "dsfield")) {
286 if (strcmp(*argv
, "inherit") == 0)
287 flags
|= IP6_TNL_F_USE_ORIG_TCLASS
;
289 if (get_u8(&uval
, *argv
, 16))
290 invarg("invalid TClass", *argv
);
291 flowinfo
|= htonl((__u32
)uval
<< 20) & IP6_FLOWINFO_TCLASS
;
292 flags
&= ~IP6_TNL_F_USE_ORIG_TCLASS
;
294 } else if (strcmp(*argv
, "flowlabel") == 0 ||
295 strcmp(*argv
, "fl") == 0) {
299 if (strcmp(*argv
, "inherit") == 0)
300 flags
|= IP6_TNL_F_USE_ORIG_FLOWLABEL
;
302 if (get_u32(&uval
, *argv
, 16))
303 invarg("invalid Flowlabel", *argv
);
305 invarg("invalid Flowlabel", *argv
);
306 flowinfo
|= htonl(uval
) & IP6_FLOWINFO_FLOWLABEL
;
307 flags
&= ~IP6_TNL_F_USE_ORIG_FLOWLABEL
;
309 } else if (strcmp(*argv
, "dscp") == 0) {
311 if (strcmp(*argv
, "inherit") != 0)
312 invarg("not inherit", *argv
);
313 flags
|= IP6_TNL_F_RCV_DSCP_COPY
;
314 } else if (strcmp(*argv
, "noencap") == 0) {
315 encaptype
= TUNNEL_ENCAP_NONE
;
316 } else if (strcmp(*argv
, "encap") == 0) {
318 if (strcmp(*argv
, "fou") == 0)
319 encaptype
= TUNNEL_ENCAP_FOU
;
320 else if (strcmp(*argv
, "gue") == 0)
321 encaptype
= TUNNEL_ENCAP_GUE
;
322 else if (strcmp(*argv
, "none") == 0)
323 encaptype
= TUNNEL_ENCAP_NONE
;
325 invarg("Invalid encap type.", *argv
);
326 } else if (strcmp(*argv
, "encap-sport") == 0) {
328 if (strcmp(*argv
, "auto") == 0)
330 else if (get_u16(&encapsport
, *argv
, 0))
331 invarg("Invalid source port.", *argv
);
332 } else if (strcmp(*argv
, "encap-dport") == 0) {
334 if (get_u16(&encapdport
, *argv
, 0))
335 invarg("Invalid destination port.", *argv
);
336 } else if (strcmp(*argv
, "encap-csum") == 0) {
337 encapflags
|= TUNNEL_ENCAP_FLAG_CSUM
;
338 } else if (strcmp(*argv
, "noencap-csum") == 0) {
339 encapflags
&= ~TUNNEL_ENCAP_FLAG_CSUM
;
340 } else if (strcmp(*argv
, "encap-udp6-csum") == 0) {
341 encapflags
|= TUNNEL_ENCAP_FLAG_CSUM6
;
342 } else if (strcmp(*argv
, "noencap-udp6-csum") == 0) {
343 encapflags
&= ~TUNNEL_ENCAP_FLAG_CSUM6
;
344 } else if (strcmp(*argv
, "encap-remcsum") == 0) {
345 encapflags
|= TUNNEL_ENCAP_FLAG_REMCSUM
;
346 } else if (strcmp(*argv
, "noencap-remcsum") == 0) {
347 encapflags
&= ~TUNNEL_ENCAP_FLAG_REMCSUM
;
348 } else if (strcmp(*argv
, "fwmark") == 0) {
350 if (strcmp(*argv
, "inherit") == 0) {
351 flags
|= IP6_TNL_F_USE_ORIG_FWMARK
;
354 if (get_u32(&fwmark
, *argv
, 0))
355 invarg("invalid fwmark\n", *argv
);
356 flags
&= ~IP6_TNL_F_USE_ORIG_FWMARK
;
358 } else if (strcmp(*argv
, "encaplimit") == 0) {
360 if (strcmp(*argv
, "none") == 0) {
361 flags
|= IP6_TNL_F_IGN_ENCAP_LIMIT
;
365 if (get_u8(&uval
, *argv
, 0) < -1)
366 invarg("invalid ELIM", *argv
);
368 flags
&= ~IP6_TNL_F_IGN_ENCAP_LIMIT
;
375 addattr32(n
, 1024, IFLA_GRE_IKEY
, ikey
);
376 addattr32(n
, 1024, IFLA_GRE_OKEY
, okey
);
377 addattr_l(n
, 1024, IFLA_GRE_IFLAGS
, &iflags
, 2);
378 addattr_l(n
, 1024, IFLA_GRE_OFLAGS
, &oflags
, 2);
379 addattr_l(n
, 1024, IFLA_GRE_LOCAL
, &laddr
, sizeof(laddr
));
380 addattr_l(n
, 1024, IFLA_GRE_REMOTE
, &raddr
, sizeof(raddr
));
382 addattr32(n
, 1024, IFLA_GRE_LINK
, link
);
383 addattr_l(n
, 1024, IFLA_GRE_TTL
, &hop_limit
, 1);
384 addattr_l(n
, 1024, IFLA_GRE_ENCAP_LIMIT
, &encap_limit
, 1);
385 addattr_l(n
, 1024, IFLA_GRE_FLOWINFO
, &flowinfo
, 4);
386 addattr32(n
, 1024, IFLA_GRE_FLAGS
, flags
);
387 addattr32(n
, 1024, IFLA_GRE_FWMARK
, fwmark
);
389 addattr16(n
, 1024, IFLA_GRE_ENCAP_TYPE
, encaptype
);
390 addattr16(n
, 1024, IFLA_GRE_ENCAP_FLAGS
, encapflags
);
391 addattr16(n
, 1024, IFLA_GRE_ENCAP_SPORT
, htons(encapsport
));
392 addattr16(n
, 1024, IFLA_GRE_ENCAP_DPORT
, htons(encapdport
));
397 static void gre_print_opt(struct link_util
*lu
, FILE *f
, struct rtattr
*tb
[])
400 const char *local
= "any";
401 const char *remote
= "any";
402 unsigned int iflags
= 0;
403 unsigned int oflags
= 0;
404 unsigned int flags
= 0;
405 unsigned int flowinfo
= 0;
406 struct in6_addr in6_addr_any
= IN6ADDR_ANY_INIT
;
411 if (tb
[IFLA_GRE_FLAGS
])
412 flags
= rta_getattr_u32(tb
[IFLA_GRE_FLAGS
]);
414 if (tb
[IFLA_GRE_FLOWINFO
])
415 flowinfo
= rta_getattr_u32(tb
[IFLA_GRE_FLOWINFO
]);
417 if (tb
[IFLA_GRE_REMOTE
]) {
418 struct in6_addr addr
;
420 memcpy(&addr
, RTA_DATA(tb
[IFLA_GRE_REMOTE
]), sizeof(addr
));
422 if (memcmp(&addr
, &in6_addr_any
, sizeof(addr
)))
423 remote
= format_host(AF_INET6
, sizeof(addr
), &addr
);
426 fprintf(f
, "remote %s ", remote
);
428 if (tb
[IFLA_GRE_LOCAL
]) {
429 struct in6_addr addr
;
431 memcpy(&addr
, RTA_DATA(tb
[IFLA_GRE_LOCAL
]), sizeof(addr
));
433 if (memcmp(&addr
, &in6_addr_any
, sizeof(addr
)))
434 local
= format_host(AF_INET6
, sizeof(addr
), &addr
);
437 fprintf(f
, "local %s ", local
);
439 if (tb
[IFLA_GRE_LINK
] && rta_getattr_u32(tb
[IFLA_GRE_LINK
])) {
440 unsigned int link
= rta_getattr_u32(tb
[IFLA_GRE_LINK
]);
441 const char *n
= if_indextoname(link
, s2
);
444 fprintf(f
, "dev %s ", n
);
446 fprintf(f
, "dev %u ", link
);
449 if (tb
[IFLA_GRE_TTL
] && rta_getattr_u8(tb
[IFLA_GRE_TTL
]))
450 fprintf(f
, "hoplimit %d ", rta_getattr_u8(tb
[IFLA_GRE_TTL
]));
452 if (flags
& IP6_TNL_F_IGN_ENCAP_LIMIT
)
453 fprintf(f
, "encaplimit none ");
454 else if (tb
[IFLA_GRE_ENCAP_LIMIT
]) {
455 int encap_limit
= rta_getattr_u8(tb
[IFLA_GRE_ENCAP_LIMIT
]);
457 fprintf(f
, "encaplimit %d ", encap_limit
);
460 if (flags
& IP6_TNL_F_USE_ORIG_FLOWLABEL
)
461 fprintf(f
, "flowlabel inherit ");
463 fprintf(f
, "flowlabel 0x%05x ", ntohl(flowinfo
& IP6_FLOWINFO_FLOWLABEL
));
465 if (flags
& IP6_TNL_F_RCV_DSCP_COPY
)
466 fprintf(f
, "dscp inherit ");
468 if (tb
[IFLA_GRE_IFLAGS
])
469 iflags
= rta_getattr_u16(tb
[IFLA_GRE_IFLAGS
]);
471 if (tb
[IFLA_GRE_OFLAGS
])
472 oflags
= rta_getattr_u16(tb
[IFLA_GRE_OFLAGS
]);
474 if ((iflags
& GRE_KEY
) && tb
[IFLA_GRE_IKEY
]) {
475 inet_ntop(AF_INET
, RTA_DATA(tb
[IFLA_GRE_IKEY
]), s2
, sizeof(s2
));
476 fprintf(f
, "ikey %s ", s2
);
479 if ((oflags
& GRE_KEY
) && tb
[IFLA_GRE_OKEY
]) {
480 inet_ntop(AF_INET
, RTA_DATA(tb
[IFLA_GRE_OKEY
]), s2
, sizeof(s2
));
481 fprintf(f
, "okey %s ", s2
);
484 if (iflags
& GRE_SEQ
)
486 if (oflags
& GRE_SEQ
)
488 if (iflags
& GRE_CSUM
)
490 if (oflags
& GRE_CSUM
)
493 if (flags
& IP6_TNL_F_USE_ORIG_FWMARK
)
494 fprintf(f
, "fwmark inherit ");
495 else if (tb
[IFLA_GRE_FWMARK
] && rta_getattr_u32(tb
[IFLA_GRE_FWMARK
]))
496 fprintf(f
, "fwmark 0x%x ", rta_getattr_u32(tb
[IFLA_GRE_FWMARK
]));
498 if (tb
[IFLA_GRE_ENCAP_TYPE
] &&
499 rta_getattr_u16(tb
[IFLA_GRE_ENCAP_TYPE
]) != TUNNEL_ENCAP_NONE
) {
500 __u16 type
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_TYPE
]);
501 __u16 flags
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_FLAGS
]);
502 __u16 sport
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_SPORT
]);
503 __u16 dport
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_DPORT
]);
507 case TUNNEL_ENCAP_FOU
:
510 case TUNNEL_ENCAP_GUE
:
514 fputs("unknown ", f
);
519 fputs("encap-sport auto ", f
);
521 fprintf(f
, "encap-sport %u", ntohs(sport
));
523 fprintf(f
, "encap-dport %u ", ntohs(dport
));
525 if (flags
& TUNNEL_ENCAP_FLAG_CSUM
)
526 fputs("encap-csum ", f
);
528 fputs("noencap-csum ", f
);
530 if (flags
& TUNNEL_ENCAP_FLAG_CSUM6
)
531 fputs("encap-csum6 ", f
);
533 fputs("noencap-csum6 ", f
);
535 if (flags
& TUNNEL_ENCAP_FLAG_REMCSUM
)
536 fputs("encap-remcsum ", f
);
538 fputs("noencap-remcsum ", f
);
542 static void gre_print_help(struct link_util
*lu
, int argc
, char **argv
,
548 struct link_util ip6gre_link_util
= {
550 .maxattr
= IFLA_GRE_MAX
,
551 .parse_opt
= gre_parse_opt
,
552 .print_opt
= gre_print_opt
,
553 .print_help
= gre_print_help
,
556 struct link_util ip6gretap_link_util
= {
558 .maxattr
= IFLA_GRE_MAX
,
559 .parse_opt
= gre_parse_opt
,
560 .print_opt
= gre_print_opt
,
561 .print_help
= gre_print_help
,