2 * link_gre.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: Herbert Xu <herbert@gondor.apana.org.au>
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <arpa/inet.h>
20 #include <linux/if_tunnel.h>
23 #include "ip_common.h"
26 static void print_usage(FILE *f
)
29 "Usage: ... { gre | gretap } [ remote ADDR ]\n"
39 " [ encap { fou | gue | none } ]\n"
40 " [ encap-sport PORT ]\n"
41 " [ encap-dport PORT ]\n"
42 " [ [no]encap-csum ]\n"
43 " [ [no]encap-csum6 ]\n"
44 " [ [no]encap-remcsum ]\n"
47 "Where: ADDR := { IP_ADDRESS | any }\n"
48 " TOS := { NUMBER | inherit }\n"
49 " TTL := { 1..255 | inherit }\n"
50 " KEY := { DOTTED_QUAD | NUMBER }\n"
51 " MARK := { 0x0..0xffffffff }\n"
55 static void usage(void) __attribute__((noreturn
));
56 static void usage(void)
62 static int gre_parse_opt(struct link_util
*lu
, int argc
, char **argv
,
65 struct ifinfomsg
*ifi
= (struct ifinfomsg
*)(n
+ 1);
71 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(*ifi
)),
72 .n
.nlmsg_flags
= NLM_F_REQUEST
,
73 .n
.nlmsg_type
= RTM_GETLINK
,
74 .i
.ifi_family
= preferred_family
,
75 .i
.ifi_index
= ifi
->ifi_index
,
77 struct rtattr
*tb
[IFLA_MAX
+ 1];
78 struct rtattr
*linkinfo
[IFLA_INFO_MAX
+1];
79 struct rtattr
*greinfo
[IFLA_GRE_MAX
+ 1];
82 unsigned int ikey
= 0;
83 unsigned int okey
= 0;
84 unsigned int saddr
= 0;
85 unsigned int daddr
= 0;
86 unsigned int link
= 0;
98 if (!(n
->nlmsg_flags
& NLM_F_CREATE
)) {
99 if (rtnl_talk(&rth
, &req
.n
, &req
.n
, sizeof(req
)) < 0) {
102 "Failed to get existing tunnel info.\n");
106 len
= req
.n
.nlmsg_len
;
107 len
-= NLMSG_LENGTH(sizeof(*ifi
));
111 parse_rtattr(tb
, IFLA_MAX
, IFLA_RTA(&req
.i
), len
);
113 if (!tb
[IFLA_LINKINFO
])
116 parse_rtattr_nested(linkinfo
, IFLA_INFO_MAX
, tb
[IFLA_LINKINFO
]);
118 if (!linkinfo
[IFLA_INFO_DATA
])
121 parse_rtattr_nested(greinfo
, IFLA_GRE_MAX
,
122 linkinfo
[IFLA_INFO_DATA
]);
124 if (greinfo
[IFLA_GRE_IKEY
])
125 ikey
= rta_getattr_u32(greinfo
[IFLA_GRE_IKEY
]);
127 if (greinfo
[IFLA_GRE_OKEY
])
128 okey
= rta_getattr_u32(greinfo
[IFLA_GRE_OKEY
]);
130 if (greinfo
[IFLA_GRE_IFLAGS
])
131 iflags
= rta_getattr_u16(greinfo
[IFLA_GRE_IFLAGS
]);
133 if (greinfo
[IFLA_GRE_OFLAGS
])
134 oflags
= rta_getattr_u16(greinfo
[IFLA_GRE_OFLAGS
]);
136 if (greinfo
[IFLA_GRE_LOCAL
])
137 saddr
= rta_getattr_u32(greinfo
[IFLA_GRE_LOCAL
]);
139 if (greinfo
[IFLA_GRE_REMOTE
])
140 daddr
= rta_getattr_u32(greinfo
[IFLA_GRE_REMOTE
]);
142 if (greinfo
[IFLA_GRE_PMTUDISC
])
143 pmtudisc
= rta_getattr_u8(
144 greinfo
[IFLA_GRE_PMTUDISC
]);
146 if (greinfo
[IFLA_GRE_TTL
])
147 ttl
= rta_getattr_u8(greinfo
[IFLA_GRE_TTL
]);
149 if (greinfo
[IFLA_GRE_TOS
])
150 tos
= rta_getattr_u8(greinfo
[IFLA_GRE_TOS
]);
152 if (greinfo
[IFLA_GRE_LINK
])
153 link
= rta_getattr_u8(greinfo
[IFLA_GRE_LINK
]);
155 if (greinfo
[IFLA_GRE_ENCAP_TYPE
])
156 encaptype
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_TYPE
]);
157 if (greinfo
[IFLA_GRE_ENCAP_FLAGS
])
158 encapflags
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_FLAGS
]);
159 if (greinfo
[IFLA_GRE_ENCAP_SPORT
])
160 encapsport
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_SPORT
]);
161 if (greinfo
[IFLA_GRE_ENCAP_DPORT
])
162 encapdport
= rta_getattr_u16(greinfo
[IFLA_GRE_ENCAP_DPORT
]);
164 if (greinfo
[IFLA_GRE_COLLECT_METADATA
])
167 if (greinfo
[IFLA_GRE_FWMARK
])
168 fwmark
= rta_getattr_u32(greinfo
[IFLA_GRE_FWMARK
]);
172 if (!matches(*argv
, "key")) {
178 if (strchr(*argv
, '.'))
179 uval
= get_addr32(*argv
);
181 if (get_unsigned(&uval
, *argv
, 0) < 0) {
183 "Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv
);
190 } else if (!matches(*argv
, "ikey")) {
195 if (strchr(*argv
, '.'))
196 uval
= get_addr32(*argv
);
198 if (get_unsigned(&uval
, *argv
, 0) < 0) {
199 fprintf(stderr
, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv
);
205 } else if (!matches(*argv
, "okey")) {
210 if (strchr(*argv
, '.'))
211 uval
= get_addr32(*argv
);
213 if (get_unsigned(&uval
, *argv
, 0) < 0) {
214 fprintf(stderr
, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv
);
220 } else if (!matches(*argv
, "seq")) {
223 } else if (!matches(*argv
, "iseq")) {
225 } else if (!matches(*argv
, "oseq")) {
227 } else if (!matches(*argv
, "csum")) {
230 } else if (!matches(*argv
, "icsum")) {
232 } else if (!matches(*argv
, "ocsum")) {
234 } else if (!matches(*argv
, "nopmtudisc")) {
236 } else if (!matches(*argv
, "pmtudisc")) {
238 } else if (!matches(*argv
, "remote")) {
240 if (strcmp(*argv
, "any"))
241 daddr
= get_addr32(*argv
);
242 } else if (!matches(*argv
, "local")) {
244 if (strcmp(*argv
, "any"))
245 saddr
= get_addr32(*argv
);
246 } else if (!matches(*argv
, "dev")) {
248 link
= if_nametoindex(*argv
);
250 fprintf(stderr
, "Cannot find device \"%s\"\n",
254 } else if (!matches(*argv
, "ttl") ||
255 !matches(*argv
, "hoplimit")) {
259 if (strcmp(*argv
, "inherit") != 0) {
260 if (get_unsigned(&uval
, *argv
, 0))
261 invarg("invalid TTL\n", *argv
);
263 invarg("TTL must be <= 255\n", *argv
);
266 } else if (!matches(*argv
, "tos") ||
267 !matches(*argv
, "tclass") ||
268 !matches(*argv
, "dsfield")) {
272 if (strcmp(*argv
, "inherit") != 0) {
273 if (rtnl_dsfield_a2n(&uval
, *argv
))
274 invarg("bad TOS value", *argv
);
278 } else if (strcmp(*argv
, "noencap") == 0) {
279 encaptype
= TUNNEL_ENCAP_NONE
;
280 } else if (strcmp(*argv
, "encap") == 0) {
282 if (strcmp(*argv
, "fou") == 0)
283 encaptype
= TUNNEL_ENCAP_FOU
;
284 else if (strcmp(*argv
, "gue") == 0)
285 encaptype
= TUNNEL_ENCAP_GUE
;
286 else if (strcmp(*argv
, "none") == 0)
287 encaptype
= TUNNEL_ENCAP_NONE
;
289 invarg("Invalid encap type.", *argv
);
290 } else if (strcmp(*argv
, "encap-sport") == 0) {
292 if (strcmp(*argv
, "auto") == 0)
294 else if (get_u16(&encapsport
, *argv
, 0))
295 invarg("Invalid source port.", *argv
);
296 } else if (strcmp(*argv
, "encap-dport") == 0) {
298 if (get_u16(&encapdport
, *argv
, 0))
299 invarg("Invalid destination port.", *argv
);
300 } else if (strcmp(*argv
, "encap-csum") == 0) {
301 encapflags
|= TUNNEL_ENCAP_FLAG_CSUM
;
302 } else if (strcmp(*argv
, "noencap-csum") == 0) {
303 encapflags
&= ~TUNNEL_ENCAP_FLAG_CSUM
;
304 } else if (strcmp(*argv
, "encap-udp6-csum") == 0) {
305 encapflags
|= TUNNEL_ENCAP_FLAG_CSUM6
;
306 } else if (strcmp(*argv
, "noencap-udp6-csum") == 0) {
307 encapflags
|= ~TUNNEL_ENCAP_FLAG_CSUM6
;
308 } else if (strcmp(*argv
, "encap-remcsum") == 0) {
309 encapflags
|= TUNNEL_ENCAP_FLAG_REMCSUM
;
310 } else if (strcmp(*argv
, "noencap-remcsum") == 0) {
311 encapflags
|= ~TUNNEL_ENCAP_FLAG_REMCSUM
;
312 } else if (strcmp(*argv
, "external") == 0) {
314 } else if (strcmp(*argv
, "fwmark") == 0) {
316 if (get_u32(&fwmark
, *argv
, 0))
317 invarg("invalid fwmark\n", *argv
);
323 if (!ikey
&& IN_MULTICAST(ntohl(daddr
))) {
327 if (!okey
&& IN_MULTICAST(ntohl(daddr
))) {
331 if (IN_MULTICAST(ntohl(daddr
)) && !saddr
) {
332 fprintf(stderr
, "A broadcast tunnel requires a source address.\n");
337 addattr32(n
, 1024, IFLA_GRE_IKEY
, ikey
);
338 addattr32(n
, 1024, IFLA_GRE_OKEY
, okey
);
339 addattr_l(n
, 1024, IFLA_GRE_IFLAGS
, &iflags
, 2);
340 addattr_l(n
, 1024, IFLA_GRE_OFLAGS
, &oflags
, 2);
341 addattr_l(n
, 1024, IFLA_GRE_LOCAL
, &saddr
, 4);
342 addattr_l(n
, 1024, IFLA_GRE_REMOTE
, &daddr
, 4);
343 addattr_l(n
, 1024, IFLA_GRE_PMTUDISC
, &pmtudisc
, 1);
345 addattr32(n
, 1024, IFLA_GRE_LINK
, link
);
346 addattr_l(n
, 1024, IFLA_GRE_TTL
, &ttl
, 1);
347 addattr_l(n
, 1024, IFLA_GRE_TOS
, &tos
, 1);
348 addattr32(n
, 1024, IFLA_GRE_FWMARK
, fwmark
);
350 addattr_l(n
, 1024, IFLA_GRE_COLLECT_METADATA
, NULL
, 0);
353 addattr16(n
, 1024, IFLA_GRE_ENCAP_TYPE
, encaptype
);
354 addattr16(n
, 1024, IFLA_GRE_ENCAP_FLAGS
, encapflags
);
355 addattr16(n
, 1024, IFLA_GRE_ENCAP_SPORT
, htons(encapsport
));
356 addattr16(n
, 1024, IFLA_GRE_ENCAP_DPORT
, htons(encapdport
));
361 static void gre_print_direct_opt(FILE *f
, struct rtattr
*tb
[])
364 const char *local
= "any";
365 const char *remote
= "any";
366 unsigned int iflags
= 0;
367 unsigned int oflags
= 0;
369 if (tb
[IFLA_GRE_REMOTE
]) {
370 unsigned int addr
= rta_getattr_u32(tb
[IFLA_GRE_REMOTE
]);
373 remote
= format_host(AF_INET
, 4, &addr
);
376 fprintf(f
, "remote %s ", remote
);
378 if (tb
[IFLA_GRE_LOCAL
]) {
379 unsigned int addr
= rta_getattr_u32(tb
[IFLA_GRE_LOCAL
]);
382 local
= format_host(AF_INET
, 4, &addr
);
385 fprintf(f
, "local %s ", local
);
387 if (tb
[IFLA_GRE_LINK
] && rta_getattr_u32(tb
[IFLA_GRE_LINK
])) {
388 unsigned int link
= rta_getattr_u32(tb
[IFLA_GRE_LINK
]);
389 const char *n
= if_indextoname(link
, s2
);
392 fprintf(f
, "dev %s ", n
);
394 fprintf(f
, "dev %u ", link
);
397 if (tb
[IFLA_GRE_TTL
] && rta_getattr_u8(tb
[IFLA_GRE_TTL
]))
398 fprintf(f
, "ttl %d ", rta_getattr_u8(tb
[IFLA_GRE_TTL
]));
400 fprintf(f
, "ttl inherit ");
402 if (tb
[IFLA_GRE_TOS
] && rta_getattr_u8(tb
[IFLA_GRE_TOS
])) {
403 int tos
= rta_getattr_u8(tb
[IFLA_GRE_TOS
]);
407 fputs("inherit ", f
);
409 fprintf(f
, "0x%x ", tos
);
412 if (tb
[IFLA_GRE_PMTUDISC
] &&
413 !rta_getattr_u8(tb
[IFLA_GRE_PMTUDISC
]))
414 fputs("nopmtudisc ", f
);
416 if (tb
[IFLA_GRE_IFLAGS
])
417 iflags
= rta_getattr_u16(tb
[IFLA_GRE_IFLAGS
]);
419 if (tb
[IFLA_GRE_OFLAGS
])
420 oflags
= rta_getattr_u16(tb
[IFLA_GRE_OFLAGS
]);
422 if ((iflags
& GRE_KEY
) && tb
[IFLA_GRE_IKEY
]) {
423 inet_ntop(AF_INET
, RTA_DATA(tb
[IFLA_GRE_IKEY
]), s2
, sizeof(s2
));
424 fprintf(f
, "ikey %s ", s2
);
427 if ((oflags
& GRE_KEY
) && tb
[IFLA_GRE_OKEY
]) {
428 inet_ntop(AF_INET
, RTA_DATA(tb
[IFLA_GRE_OKEY
]), s2
, sizeof(s2
));
429 fprintf(f
, "okey %s ", s2
);
432 if (iflags
& GRE_SEQ
)
434 if (oflags
& GRE_SEQ
)
436 if (iflags
& GRE_CSUM
)
438 if (oflags
& GRE_CSUM
)
441 if (tb
[IFLA_GRE_FWMARK
] && rta_getattr_u32(tb
[IFLA_GRE_FWMARK
])) {
442 fprintf(f
, "fwmark 0x%x ",
443 rta_getattr_u32(tb
[IFLA_GRE_FWMARK
]));
447 static void gre_print_opt(struct link_util
*lu
, FILE *f
, struct rtattr
*tb
[])
452 if (!tb
[IFLA_GRE_COLLECT_METADATA
])
453 gre_print_direct_opt(f
, tb
);
455 fputs("external ", f
);
457 if (tb
[IFLA_GRE_ENCAP_TYPE
] &&
458 rta_getattr_u16(tb
[IFLA_GRE_ENCAP_TYPE
]) != TUNNEL_ENCAP_NONE
) {
459 __u16 type
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_TYPE
]);
460 __u16 flags
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_FLAGS
]);
461 __u16 sport
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_SPORT
]);
462 __u16 dport
= rta_getattr_u16(tb
[IFLA_GRE_ENCAP_DPORT
]);
466 case TUNNEL_ENCAP_FOU
:
469 case TUNNEL_ENCAP_GUE
:
473 fputs("unknown ", f
);
478 fputs("encap-sport auto ", f
);
480 fprintf(f
, "encap-sport %u", ntohs(sport
));
482 fprintf(f
, "encap-dport %u ", ntohs(dport
));
484 if (flags
& TUNNEL_ENCAP_FLAG_CSUM
)
485 fputs("encap-csum ", f
);
487 fputs("noencap-csum ", f
);
489 if (flags
& TUNNEL_ENCAP_FLAG_CSUM6
)
490 fputs("encap-csum6 ", f
);
492 fputs("noencap-csum6 ", f
);
494 if (flags
& TUNNEL_ENCAP_FLAG_REMCSUM
)
495 fputs("encap-remcsum ", f
);
497 fputs("noencap-remcsum ", f
);
501 static void gre_print_help(struct link_util
*lu
, int argc
, char **argv
,
507 struct link_util gre_link_util
= {
509 .maxattr
= IFLA_GRE_MAX
,
510 .parse_opt
= gre_parse_opt
,
511 .print_opt
= gre_print_opt
,
512 .print_help
= gre_print_help
,
515 struct link_util gretap_link_util
= {
517 .maxattr
= IFLA_GRE_MAX
,
518 .parse_opt
= gre_parse_opt
,
519 .print_opt
= gre_print_opt
,
520 .print_help
= gre_print_help
,