blob: 839fb29981b679b36141d239f8a2fc9770440d91 [file] [log] [blame]
Herbert Xu237d9e82008-10-09 15:08:24 +08001/*
2 * link_gre.c gre 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: Herbert Xu <herbert@gondor.apana.org.au>
10 *
11 */
12
13#include <string.h>
14#include <net/if.h>
Herbert Xu237d9e82008-10-09 15:08:24 +080015#include <sys/types.h>
16#include <sys/socket.h>
17#include <arpa/inet.h>
18
Stephen Hemminger1957a322009-03-24 15:40:54 -070019#include <linux/ip.h>
20#include <linux/if_tunnel.h>
Herbert Xu237d9e82008-10-09 15:08:24 +080021#include "rt_names.h"
22#include "utils.h"
23#include "ip_common.h"
24#include "tunnel.h"
25
26static void usage(void) __attribute__((noreturn));
27static void usage(void)
28{
29 fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
30 fprintf(stderr, " type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
31 fprintf(stderr, " [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
32 fprintf(stderr, " [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
33 fprintf(stderr, "\n");
34 fprintf(stderr, "Where: NAME := STRING\n");
35 fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
36 fprintf(stderr, " TOS := { NUMBER | inherit }\n");
37 fprintf(stderr, " TTL := { 1..255 | inherit }\n");
38 fprintf(stderr, " KEY := { DOTTED_QUAD | NUMBER }\n");
39 exit(-1);
40}
41
42static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
43 struct nlmsghdr *n)
44{
Herbert Xu72c771b2009-01-06 18:27:52 -080045 struct {
46 struct nlmsghdr n;
47 struct ifinfomsg i;
48 char buf[1024];
49 } req;
50 struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
51 struct rtattr *tb[IFLA_MAX + 1];
52 struct rtattr *linkinfo[IFLA_INFO_MAX+1];
53 struct rtattr *greinfo[IFLA_GRE_MAX + 1];
Herbert Xu237d9e82008-10-09 15:08:24 +080054 __u16 iflags = 0;
55 __u16 oflags = 0;
56 unsigned ikey = 0;
57 unsigned okey = 0;
58 unsigned saddr = 0;
59 unsigned daddr = 0;
Herbert Xu72c771b2009-01-06 18:27:52 -080060 unsigned link = 0;
61 __u8 pmtudisc = 1;
62 __u8 ttl = 0;
63 __u8 tos = 0;
64 int len;
65
66 if (!(n->nlmsg_flags & NLM_F_CREATE)) {
67 memset(&req, 0, sizeof(req));
68
69 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
70 req.n.nlmsg_flags = NLM_F_REQUEST;
71 req.n.nlmsg_type = RTM_GETLINK;
72 req.i.ifi_family = preferred_family;
73 req.i.ifi_index = ifi->ifi_index;
74
Stephen Hemmingercd70f3f2011-12-28 10:37:12 -080075 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
Herbert Xu72c771b2009-01-06 18:27:52 -080076get_failed:
77 fprintf(stderr,
78 "Failed to get existing tunnel info.\n");
79 return -1;
80 }
81
82 len = req.n.nlmsg_len;
83 len -= NLMSG_LENGTH(sizeof(*ifi));
84 if (len < 0)
85 goto get_failed;
86
87 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
88
89 if (!tb[IFLA_LINKINFO])
90 goto get_failed;
91
92 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
93
94 if (!linkinfo[IFLA_INFO_DATA])
95 goto get_failed;
96
97 parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
98 linkinfo[IFLA_INFO_DATA]);
99
100 if (greinfo[IFLA_GRE_IKEY])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700101 ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800102
103 if (greinfo[IFLA_GRE_OKEY])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700104 okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800105
106 if (greinfo[IFLA_GRE_IFLAGS])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700107 iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800108
109 if (greinfo[IFLA_GRE_OFLAGS])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700110 oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800111
112 if (greinfo[IFLA_GRE_LOCAL])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700113 saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800114
115 if (greinfo[IFLA_GRE_REMOTE])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700116 daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800117
118 if (greinfo[IFLA_GRE_PMTUDISC])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700119 pmtudisc = rta_getattr_u8(
Herbert Xu72c771b2009-01-06 18:27:52 -0800120 greinfo[IFLA_GRE_PMTUDISC]);
121
122 if (greinfo[IFLA_GRE_TTL])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700123 ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800124
125 if (greinfo[IFLA_GRE_TOS])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700126 tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800127
128 if (greinfo[IFLA_GRE_LINK])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700129 link = rta_getattr_u8(greinfo[IFLA_GRE_LINK]);
Herbert Xu72c771b2009-01-06 18:27:52 -0800130 }
Herbert Xu237d9e82008-10-09 15:08:24 +0800131
132 while (argc > 0) {
133 if (!matches(*argv, "key")) {
134 unsigned uval;
135
136 NEXT_ARG();
137 iflags |= GRE_KEY;
138 oflags |= GRE_KEY;
139 if (strchr(*argv, '.'))
140 uval = get_addr32(*argv);
141 else {
142 if (get_unsigned(&uval, *argv, 0) < 0) {
143 fprintf(stderr,
144 "Invalid value for \"key\"\n");
145 exit(-1);
146 }
147 uval = htonl(uval);
148 }
149
150 ikey = okey = uval;
151 } else if (!matches(*argv, "ikey")) {
152 unsigned uval;
153
154 NEXT_ARG();
155 iflags |= GRE_KEY;
156 if (strchr(*argv, '.'))
157 uval = get_addr32(*argv);
158 else {
159 if (get_unsigned(&uval, *argv, 0)<0) {
160 fprintf(stderr, "invalid value of \"ikey\"\n");
161 exit(-1);
162 }
163 uval = htonl(uval);
164 }
165 ikey = uval;
166 } else if (!matches(*argv, "okey")) {
167 unsigned uval;
168
169 NEXT_ARG();
170 oflags |= GRE_KEY;
171 if (strchr(*argv, '.'))
172 uval = get_addr32(*argv);
173 else {
174 if (get_unsigned(&uval, *argv, 0)<0) {
175 fprintf(stderr, "invalid value of \"okey\"\n");
176 exit(-1);
177 }
178 uval = htonl(uval);
179 }
180 okey = uval;
181 } else if (!matches(*argv, "seq")) {
182 iflags |= GRE_SEQ;
183 oflags |= GRE_SEQ;
184 } else if (!matches(*argv, "iseq")) {
185 iflags |= GRE_SEQ;
186 } else if (!matches(*argv, "oseq")) {
187 oflags |= GRE_SEQ;
188 } else if (!matches(*argv, "csum")) {
189 iflags |= GRE_CSUM;
190 oflags |= GRE_CSUM;
191 } else if (!matches(*argv, "icsum")) {
192 iflags |= GRE_CSUM;
193 } else if (!matches(*argv, "ocsum")) {
194 oflags |= GRE_CSUM;
195 } else if (!matches(*argv, "nopmtudisc")) {
Herbert Xu72c771b2009-01-06 18:27:52 -0800196 pmtudisc = 0;
Herbert Xu237d9e82008-10-09 15:08:24 +0800197 } else if (!matches(*argv, "pmtudisc")) {
Herbert Xu72c771b2009-01-06 18:27:52 -0800198 pmtudisc = 1;
Herbert Xu237d9e82008-10-09 15:08:24 +0800199 } else if (!matches(*argv, "remote")) {
200 NEXT_ARG();
201 if (strcmp(*argv, "any"))
202 daddr = get_addr32(*argv);
203 } else if (!matches(*argv, "local")) {
204 NEXT_ARG();
205 if (strcmp(*argv, "any"))
206 saddr = get_addr32(*argv);
207 } else if (!matches(*argv, "dev")) {
Herbert Xu237d9e82008-10-09 15:08:24 +0800208 NEXT_ARG();
Stephen Hemmingerea71bea2010-11-28 10:35:28 -0800209 link = if_nametoindex(*argv);
Herbert Xu237d9e82008-10-09 15:08:24 +0800210 if (link == 0)
211 exit(-1);
Herbert Xu237d9e82008-10-09 15:08:24 +0800212 } else if (!matches(*argv, "ttl") ||
213 !matches(*argv, "hoplimit")) {
214 unsigned uval;
Herbert Xu237d9e82008-10-09 15:08:24 +0800215
216 NEXT_ARG();
217 if (strcmp(*argv, "inherit") != 0) {
218 if (get_unsigned(&uval, *argv, 0))
219 invarg("invalid TTL\n", *argv);
220 if (uval > 255)
221 invarg("TTL must be <= 255\n", *argv);
222 ttl = uval;
Herbert Xu237d9e82008-10-09 15:08:24 +0800223 }
224 } else if (!matches(*argv, "tos") ||
225 !matches(*argv, "tclass") ||
226 !matches(*argv, "dsfield")) {
227 __u32 uval;
Herbert Xu237d9e82008-10-09 15:08:24 +0800228
229 NEXT_ARG();
230 if (strcmp(*argv, "inherit") != 0) {
231 if (rtnl_dsfield_a2n(&uval, *argv))
232 invarg("bad TOS value", *argv);
233 tos = uval;
234 } else
235 tos = 1;
Herbert Xu237d9e82008-10-09 15:08:24 +0800236 } else
237 usage();
238 argc--; argv++;
239 }
240
241 if (!ikey && IN_MULTICAST(ntohl(daddr))) {
242 ikey = daddr;
243 iflags |= GRE_KEY;
244 }
245 if (!okey && IN_MULTICAST(ntohl(daddr))) {
246 okey = daddr;
247 oflags |= GRE_KEY;
248 }
249 if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
250 fprintf(stderr, "Broadcast tunnel requires a source address.\n");
251 return -1;
252 }
253
254 addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
255 addattr32(n, 1024, IFLA_GRE_OKEY, okey);
256 addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
257 addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
258 addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
259 addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
Herbert Xu72c771b2009-01-06 18:27:52 -0800260 addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
261 if (link)
262 addattr32(n, 1024, IFLA_GRE_LINK, link);
263 addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
264 addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
Herbert Xu237d9e82008-10-09 15:08:24 +0800265
266 return 0;
267}
268
269static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
270{
271 char s1[1024];
272 char s2[64];
273 const char *local = "any";
274 const char *remote = "any";
275 unsigned iflags = 0;
276 unsigned oflags = 0;
277
278 if (!tb)
279 return;
280
281 if (tb[IFLA_GRE_REMOTE]) {
Stephen Hemmingerff247462012-04-10 08:47:55 -0700282 unsigned addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]);
Herbert Xu237d9e82008-10-09 15:08:24 +0800283
284 if (addr)
285 remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
286 }
287
288 fprintf(f, "remote %s ", remote);
289
290 if (tb[IFLA_GRE_LOCAL]) {
Stephen Hemmingerff247462012-04-10 08:47:55 -0700291 unsigned addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);
Herbert Xu237d9e82008-10-09 15:08:24 +0800292
293 if (addr)
294 local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
295 }
296
297 fprintf(f, "local %s ", local);
298
Stephen Hemmingerff247462012-04-10 08:47:55 -0700299 if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
300 unsigned link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
Stephen Hemmingerea71bea2010-11-28 10:35:28 -0800301 const char *n = if_indextoname(link, s2);
Herbert Xu237d9e82008-10-09 15:08:24 +0800302
303 if (n)
304 fprintf(f, "dev %s ", n);
305 else
306 fprintf(f, "dev %u ", link);
307 }
308
Stephen Hemmingerff247462012-04-10 08:47:55 -0700309 if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
310 fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
Herbert Xu237d9e82008-10-09 15:08:24 +0800311 else
312 fprintf(f, "ttl inherit ");
313
Stephen Hemmingerff247462012-04-10 08:47:55 -0700314 if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
315 int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);
Herbert Xu237d9e82008-10-09 15:08:24 +0800316
317 fputs("tos ", f);
318 if (tos == 1)
319 fputs("inherit ", f);
320 else
321 fprintf(f, "0x%x ", tos);
322 }
323
324 if (tb[IFLA_GRE_PMTUDISC] &&
Stephen Hemmingerff247462012-04-10 08:47:55 -0700325 !rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
Herbert Xu237d9e82008-10-09 15:08:24 +0800326 fputs("nopmtudisc ", f);
327
328 if (tb[IFLA_GRE_IFLAGS])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700329 iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);
Herbert Xu237d9e82008-10-09 15:08:24 +0800330
331 if (tb[IFLA_GRE_OFLAGS])
Stephen Hemmingerff247462012-04-10 08:47:55 -0700332 oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);
Herbert Xu237d9e82008-10-09 15:08:24 +0800333
Stephen Hemminger71816552012-03-19 17:18:49 -0700334 if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
Herbert Xu237d9e82008-10-09 15:08:24 +0800335 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
336 fprintf(f, "ikey %s ", s2);
337 }
338
Stephen Hemminger71816552012-03-19 17:18:49 -0700339 if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
Herbert Xu237d9e82008-10-09 15:08:24 +0800340 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
Stephen Hemminger71816552012-03-19 17:18:49 -0700341 fprintf(f, "okey %s ", s2);
Herbert Xu237d9e82008-10-09 15:08:24 +0800342 }
343
344 if (iflags & GRE_SEQ)
345 fputs("iseq ", f);
346 if (oflags & GRE_SEQ)
347 fputs("oseq ", f);
348 if (iflags & GRE_CSUM)
349 fputs("icsum ", f);
350 if (oflags & GRE_CSUM)
351 fputs("ocsum ", f);
352}
353
354struct link_util gre_link_util = {
355 .id = "gre",
356 .maxattr = IFLA_GRE_MAX,
357 .parse_opt = gre_parse_opt,
358 .print_opt = gre_print_opt,
359};
360
361struct link_util gretap_link_util = {
362 .id = "gretap",
363 .maxattr = IFLA_GRE_MAX,
364 .parse_opt = gre_parse_opt,
365 .print_opt = gre_print_opt,
366};