Tweaks
[iproute2.git] / ip / link_gre.c
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 <linux/if_tunnel.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <arpa/inet.h>
19
20 #include "rt_names.h"
21 #include "utils.h"
22 #include "ip_common.h"
23 #include "tunnel.h"
24
25 static void usage(void) __attribute__((noreturn));
26 static void usage(void)
27 {
28         fprintf(stderr, "Usage: ip link { add | set | change | replace | del } NAME\n");
29         fprintf(stderr, "          type { gre | gretap } [ remote ADDR ] [ local ADDR ]\n");
30         fprintf(stderr, "          [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]\n");
31         fprintf(stderr, "          [ ttl TTL ] [ tos TOS ] [ [no]pmtudisc ] [ dev PHYS_DEV ]\n");
32         fprintf(stderr, "\n");
33         fprintf(stderr, "Where: NAME := STRING\n");
34         fprintf(stderr, "       ADDR := { IP_ADDRESS | any }\n");
35         fprintf(stderr, "       TOS  := { NUMBER | inherit }\n");
36         fprintf(stderr, "       TTL  := { 1..255 | inherit }\n");
37         fprintf(stderr, "       KEY  := { DOTTED_QUAD | NUMBER }\n");
38         exit(-1);
39 }
40
41 static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
42                          struct nlmsghdr *n)
43 {
44         struct {
45                 struct nlmsghdr n;
46                 struct ifinfomsg i;
47                 char buf[1024];
48         } req;
49         struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
50         struct rtattr *tb[IFLA_MAX + 1];
51         struct rtattr *linkinfo[IFLA_INFO_MAX+1];
52         struct rtattr *greinfo[IFLA_GRE_MAX + 1];
53         __u16 iflags = 0;
54         __u16 oflags = 0;
55         unsigned ikey = 0;
56         unsigned okey = 0;
57         unsigned saddr = 0;
58         unsigned daddr = 0;
59         unsigned link = 0;
60         __u8 pmtudisc = 1;
61         __u8 ttl = 0;
62         __u8 tos = 0;
63         int len;
64
65         if (!(n->nlmsg_flags & NLM_F_CREATE)) {
66                 memset(&req, 0, sizeof(req));
67
68                 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
69                 req.n.nlmsg_flags = NLM_F_REQUEST;
70                 req.n.nlmsg_type = RTM_GETLINK;
71                 req.i.ifi_family = preferred_family;
72                 req.i.ifi_index = ifi->ifi_index;
73
74                 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
75 get_failed:
76                         fprintf(stderr,
77                                 "Failed to get existing tunnel info.\n");
78                         return -1;
79                 }
80
81                 len = req.n.nlmsg_len;
82                 len -= NLMSG_LENGTH(sizeof(*ifi));
83                 if (len < 0)
84                         goto get_failed;
85
86                 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);
87
88                 if (!tb[IFLA_LINKINFO])
89                         goto get_failed;
90
91                 parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
92
93                 if (!linkinfo[IFLA_INFO_DATA])
94                         goto get_failed;
95
96                 parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
97                                     linkinfo[IFLA_INFO_DATA]);
98
99                 if (greinfo[IFLA_GRE_IKEY])
100                         ikey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_IKEY]);
101
102                 if (greinfo[IFLA_GRE_OKEY])
103                         okey = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_OKEY]);
104
105                 if (greinfo[IFLA_GRE_IFLAGS])
106                         iflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_IFLAGS]);
107
108                 if (greinfo[IFLA_GRE_OFLAGS])
109                         oflags = *(__u16 *)RTA_DATA(greinfo[IFLA_GRE_OFLAGS]);
110
111                 if (greinfo[IFLA_GRE_LOCAL])
112                         saddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_LOCAL]);
113
114                 if (greinfo[IFLA_GRE_REMOTE])
115                         daddr = *(__u32 *)RTA_DATA(greinfo[IFLA_GRE_REMOTE]);
116
117                 if (greinfo[IFLA_GRE_PMTUDISC])
118                         pmtudisc = *(__u8 *)RTA_DATA(
119                                 greinfo[IFLA_GRE_PMTUDISC]);
120
121                 if (greinfo[IFLA_GRE_TTL])
122                         ttl = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TTL]);
123
124                 if (greinfo[IFLA_GRE_TOS])
125                         tos = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_TOS]);
126
127                 if (greinfo[IFLA_GRE_LINK])
128                         link = *(__u8 *)RTA_DATA(greinfo[IFLA_GRE_LINK]);
129         }
130
131         while (argc > 0) {
132                 if (!matches(*argv, "key")) {
133                         unsigned uval;
134
135                         NEXT_ARG();
136                         iflags |= GRE_KEY;
137                         oflags |= GRE_KEY;
138                         if (strchr(*argv, '.'))
139                                 uval = get_addr32(*argv);
140                         else {
141                                 if (get_unsigned(&uval, *argv, 0) < 0) {
142                                         fprintf(stderr,
143                                                 "Invalid value for \"key\"\n");
144                                         exit(-1);
145                                 }
146                                 uval = htonl(uval);
147                         }
148
149                         ikey = okey = uval;
150                 } else if (!matches(*argv, "ikey")) {
151                         unsigned uval;
152
153                         NEXT_ARG();
154                         iflags |= GRE_KEY;
155                         if (strchr(*argv, '.'))
156                                 uval = get_addr32(*argv);
157                         else {
158                                 if (get_unsigned(&uval, *argv, 0)<0) {
159                                         fprintf(stderr, "invalid value of \"ikey\"\n");
160                                         exit(-1);
161                                 }
162                                 uval = htonl(uval);
163                         }
164                         ikey = uval;
165                 } else if (!matches(*argv, "okey")) {
166                         unsigned uval;
167
168                         NEXT_ARG();
169                         oflags |= GRE_KEY;
170                         if (strchr(*argv, '.'))
171                                 uval = get_addr32(*argv);
172                         else {
173                                 if (get_unsigned(&uval, *argv, 0)<0) {
174                                         fprintf(stderr, "invalid value of \"okey\"\n");
175                                         exit(-1);
176                                 }
177                                 uval = htonl(uval);
178                         }
179                         okey = uval;
180                 } else if (!matches(*argv, "seq")) {
181                         iflags |= GRE_SEQ;
182                         oflags |= GRE_SEQ;
183                 } else if (!matches(*argv, "iseq")) {
184                         iflags |= GRE_SEQ;
185                 } else if (!matches(*argv, "oseq")) {
186                         oflags |= GRE_SEQ;
187                 } else if (!matches(*argv, "csum")) {
188                         iflags |= GRE_CSUM;
189                         oflags |= GRE_CSUM;
190                 } else if (!matches(*argv, "icsum")) {
191                         iflags |= GRE_CSUM;
192                 } else if (!matches(*argv, "ocsum")) {
193                         oflags |= GRE_CSUM;
194                 } else if (!matches(*argv, "nopmtudisc")) {
195                         pmtudisc = 0;
196                 } else if (!matches(*argv, "pmtudisc")) {
197                         pmtudisc = 1;
198                 } else if (!matches(*argv, "remote")) {
199                         NEXT_ARG();
200                         if (strcmp(*argv, "any"))
201                                 daddr = get_addr32(*argv);
202                 } else if (!matches(*argv, "local")) {
203                         NEXT_ARG();
204                         if (strcmp(*argv, "any"))
205                                 saddr = get_addr32(*argv);
206                 } else if (!matches(*argv, "dev")) {
207                         NEXT_ARG();
208                         link = tnl_ioctl_get_ifindex(*argv);
209                         if (link == 0)
210                                 exit(-1);
211                 } else if (!matches(*argv, "ttl") ||
212                            !matches(*argv, "hoplimit")) {
213                         unsigned uval;
214
215                         NEXT_ARG();
216                         if (strcmp(*argv, "inherit") != 0) {
217                                 if (get_unsigned(&uval, *argv, 0))
218                                         invarg("invalid TTL\n", *argv);
219                                 if (uval > 255)
220                                         invarg("TTL must be <= 255\n", *argv);
221                                 ttl = uval;
222                         }
223                 } else if (!matches(*argv, "tos") ||
224                            !matches(*argv, "tclass") ||
225                            !matches(*argv, "dsfield")) {
226                         __u32 uval;
227
228                         NEXT_ARG();
229                         if (strcmp(*argv, "inherit") != 0) {
230                                 if (rtnl_dsfield_a2n(&uval, *argv))
231                                         invarg("bad TOS value", *argv);
232                                 tos = uval;
233                         } else
234                                 tos = 1;
235                 } else 
236                         usage();
237                 argc--; argv++;
238         }
239
240         if (!ikey && IN_MULTICAST(ntohl(daddr))) {
241                 ikey = daddr;
242                 iflags |= GRE_KEY;
243         }
244         if (!okey && IN_MULTICAST(ntohl(daddr))) {
245                 okey = daddr;
246                 oflags |= GRE_KEY;
247         }
248         if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
249                 fprintf(stderr, "Broadcast tunnel requires a source address.\n");
250                 return -1;
251         }
252
253         addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
254         addattr32(n, 1024, IFLA_GRE_OKEY, okey);
255         addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
256         addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
257         addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
258         addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
259         addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
260         if (link)
261                 addattr32(n, 1024, IFLA_GRE_LINK, link);
262         addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
263         addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
264
265         return 0;
266 }
267
268 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
269 {
270         char s1[1024];
271         char s2[64];
272         const char *local = "any";
273         const char *remote = "any";
274         unsigned iflags = 0;
275         unsigned oflags = 0;
276
277         if (!tb)
278                 return;
279
280         if (tb[IFLA_GRE_REMOTE]) {
281                 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
282
283                 if (addr)
284                         remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
285         }
286
287         fprintf(f, "remote %s ", remote);
288
289         if (tb[IFLA_GRE_LOCAL]) {
290                 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
291
292                 if (addr)
293                         local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
294         }
295
296         fprintf(f, "local %s ", local);
297
298         if (tb[IFLA_GRE_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK])) {
299                 unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK]);
300                 char *n = tnl_ioctl_get_ifname(link);
301
302                 if (n)
303                         fprintf(f, "dev %s ", n);
304                 else
305                         fprintf(f, "dev %u ", link);
306         }
307
308         if (tb[IFLA_GRE_TTL] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]))
309                 fprintf(f, "ttl %d ", *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]));
310         else
311                 fprintf(f, "ttl inherit ");
312
313         if (tb[IFLA_GRE_TOS] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS])) {
314                 int tos = *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS]);
315
316                 fputs("tos ", f);
317                 if (tos == 1)
318                         fputs("inherit ", f);
319                 else
320                         fprintf(f, "0x%x ", tos);
321         }
322
323         if (tb[IFLA_GRE_PMTUDISC] &&
324             !*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
325                 fputs("nopmtudisc ", f);
326
327         if (tb[IFLA_GRE_IFLAGS])
328                 iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
329
330         if (tb[IFLA_GRE_OFLAGS])
331                 oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
332
333         if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
334             *(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
335                 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
336                 fprintf(f, "ikey %s ", s2);
337         }
338
339         if (oflags & GRE_KEY && tb[IFLA_GRE_OKEY] &&
340             *(__u32 *)RTA_DATA(tb[IFLA_GRE_OKEY])) {
341                 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
342                 fprintf(f, "ikey %s ", s2);
343         }
344
345         if (iflags & GRE_SEQ)
346                 fputs("iseq ", f);
347         if (oflags & GRE_SEQ)
348                 fputs("oseq ", f);
349         if (iflags & GRE_CSUM)
350                 fputs("icsum ", f);
351         if (oflags & GRE_CSUM)
352                 fputs("ocsum ", f);
353 }
354
355 struct link_util gre_link_util = {
356         .id = "gre",
357         .maxattr = IFLA_GRE_MAX,
358         .parse_opt = gre_parse_opt,
359         .print_opt = gre_print_opt,
360 };
361
362 struct link_util gretap_link_util = {
363         .id = "gretap",
364         .maxattr = IFLA_GRE_MAX,
365         .parse_opt = gre_parse_opt,
366         .print_opt = gre_print_opt,
367 };