1 /*
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>
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 "rt_names.h"
22 #include "utils.h"
23 #include "ip_common.h"
24 #include "tunnel.h"
25
26 static void usage(void) __attribute__((noreturn));
usage(void)27 static 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
gre_parse_opt(struct link_util * lu,int argc,char ** argv,struct nlmsghdr * n)42 static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
43 struct nlmsghdr *n)
44 {
45 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];
54 __u16 iflags = 0;
55 __u16 oflags = 0;
56 unsigned ikey = 0;
57 unsigned okey = 0;
58 unsigned saddr = 0;
59 unsigned daddr = 0;
60 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
75 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
76 get_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])
101 ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);
102
103 if (greinfo[IFLA_GRE_OKEY])
104 okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);
105
106 if (greinfo[IFLA_GRE_IFLAGS])
107 iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);
108
109 if (greinfo[IFLA_GRE_OFLAGS])
110 oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);
111
112 if (greinfo[IFLA_GRE_LOCAL])
113 saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);
114
115 if (greinfo[IFLA_GRE_REMOTE])
116 daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);
117
118 if (greinfo[IFLA_GRE_PMTUDISC])
119 pmtudisc = *(__u8 *)RTA_DATA(
120 greinfo[IFLA_GRE_PMTUDISC]);
121
122 if (greinfo[IFLA_GRE_TTL])
123 ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);
124
125 if (greinfo[IFLA_GRE_TOS])
126 tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);
127
128 if (greinfo[IFLA_GRE_LINK])
129 link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
130 }
131
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")) {
196 pmtudisc = 0;
197 } else if (!matches(*argv, "pmtudisc")) {
198 pmtudisc = 1;
199 } 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")) {
208 NEXT_ARG();
209 link = tnl_ioctl_get_ifindex(*argv);
210 if (link == 0)
211 exit(-1);
212 } else if (!matches(*argv, "ttl") ||
213 !matches(*argv, "hoplimit")) {
214 unsigned uval;
215
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;
223 }
224 } else if (!matches(*argv, "tos") ||
225 !matches(*argv, "tclass") ||
226 !matches(*argv, "dsfield")) {
227 __u32 uval;
228
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;
236 } 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);
260 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);
265
266 return 0;
267 }
268
gre_print_opt(struct link_util * lu,FILE * f,struct rtattr * tb[])269 static 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]) {
282 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
283
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]) {
291 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
292
293 if (addr)
294 local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
295 }
296
297 fprintf(f, "local %s ", local);
298
299 if (tb[IFLA_GRE_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK])) {
300 unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK]);
301 char *n = tnl_ioctl_get_ifname(link);
302
303 if (n)
304 fprintf(f, "dev %s ", n);
305 else
306 fprintf(f, "dev %u ", link);
307 }
308
309 if (tb[IFLA_GRE_TTL] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]))
310 fprintf(f, "ttl %d ", *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]));
311 else
312 fprintf(f, "ttl inherit ");
313
314 if (tb[IFLA_GRE_TOS] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS])) {
315 int tos = *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS]);
316
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] &&
325 !*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
326 fputs("nopmtudisc ", f);
327
328 if (tb[IFLA_GRE_IFLAGS])
329 iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
330
331 if (tb[IFLA_GRE_OFLAGS])
332 oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
333
334 if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
335 *(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
336 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
337 fprintf(f, "ikey %s ", s2);
338 }
339
340 if (oflags & GRE_KEY && tb[IFLA_GRE_OKEY] &&
341 *(__u32 *)RTA_DATA(tb[IFLA_GRE_OKEY])) {
342 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
343 fprintf(f, "ikey %s ", s2);
344 }
345
346 if (iflags & GRE_SEQ)
347 fputs("iseq ", f);
348 if (oflags & GRE_SEQ)
349 fputs("oseq ", f);
350 if (iflags & GRE_CSUM)
351 fputs("icsum ", f);
352 if (oflags & GRE_CSUM)
353 fputs("ocsum ", f);
354 }
355
356 struct link_util gre_link_util = {
357 .id = "gre",
358 .maxattr = IFLA_GRE_MAX,
359 .parse_opt = gre_parse_opt,
360 .print_opt = gre_print_opt,
361 };
362
363 struct link_util gretap_link_util = {
364 .id = "gretap",
365 .maxattr = IFLA_GRE_MAX,
366 .parse_opt = gre_parse_opt,
367 .print_opt = gre_print_opt,
368 };
369