]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/link_gre.c
ip: gre: Add GRE configuration support through rtnl_link
[lisovros/iproute2_canprio.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         __u16 iflags = 0;
45         __u16 oflags = 0;
46         unsigned ikey = 0;
47         unsigned okey = 0;
48         unsigned saddr = 0;
49         unsigned daddr = 0;
50
51         while (argc > 0) {
52                 if (!matches(*argv, "key")) {
53                         unsigned uval;
54
55                         NEXT_ARG();
56                         iflags |= GRE_KEY;
57                         oflags |= GRE_KEY;
58                         if (strchr(*argv, '.'))
59                                 uval = get_addr32(*argv);
60                         else {
61                                 if (get_unsigned(&uval, *argv, 0) < 0) {
62                                         fprintf(stderr,
63                                                 "Invalid value for \"key\"\n");
64                                         exit(-1);
65                                 }
66                                 uval = htonl(uval);
67                         }
68
69                         ikey = okey = uval;
70                 } else if (!matches(*argv, "ikey")) {
71                         unsigned uval;
72
73                         NEXT_ARG();
74                         iflags |= GRE_KEY;
75                         if (strchr(*argv, '.'))
76                                 uval = get_addr32(*argv);
77                         else {
78                                 if (get_unsigned(&uval, *argv, 0)<0) {
79                                         fprintf(stderr, "invalid value of \"ikey\"\n");
80                                         exit(-1);
81                                 }
82                                 uval = htonl(uval);
83                         }
84                         ikey = uval;
85                 } else if (!matches(*argv, "okey")) {
86                         unsigned uval;
87
88                         NEXT_ARG();
89                         oflags |= GRE_KEY;
90                         if (strchr(*argv, '.'))
91                                 uval = get_addr32(*argv);
92                         else {
93                                 if (get_unsigned(&uval, *argv, 0)<0) {
94                                         fprintf(stderr, "invalid value of \"okey\"\n");
95                                         exit(-1);
96                                 }
97                                 uval = htonl(uval);
98                         }
99                         okey = uval;
100                 } else if (!matches(*argv, "seq")) {
101                         iflags |= GRE_SEQ;
102                         oflags |= GRE_SEQ;
103                 } else if (!matches(*argv, "iseq")) {
104                         iflags |= GRE_SEQ;
105                 } else if (!matches(*argv, "oseq")) {
106                         oflags |= GRE_SEQ;
107                 } else if (!matches(*argv, "csum")) {
108                         iflags |= GRE_CSUM;
109                         oflags |= GRE_CSUM;
110                 } else if (!matches(*argv, "icsum")) {
111                         iflags |= GRE_CSUM;
112                 } else if (!matches(*argv, "ocsum")) {
113                         oflags |= GRE_CSUM;
114                 } else if (!matches(*argv, "nopmtudisc")) {
115                         __u8 val = 0;
116
117                         addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &val, 1);
118                 } else if (!matches(*argv, "pmtudisc")) {
119                         __u8 val = 1;
120
121                         addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &val, 1);
122                 } else if (!matches(*argv, "remote")) {
123                         NEXT_ARG();
124                         if (strcmp(*argv, "any"))
125                                 daddr = get_addr32(*argv);
126                 } else if (!matches(*argv, "local")) {
127                         NEXT_ARG();
128                         if (strcmp(*argv, "any"))
129                                 saddr = get_addr32(*argv);
130                 } else if (!matches(*argv, "dev")) {
131                         unsigned link;
132
133                         NEXT_ARG();
134                         link = tnl_ioctl_get_ifindex(*argv);
135                         if (link == 0)
136                                 exit(-1);
137
138                         addattr32(n, 1024, IFLA_GRE_LINK, link);
139                 } else if (!matches(*argv, "ttl") ||
140                            !matches(*argv, "hoplimit")) {
141                         unsigned uval;
142                         __u8 ttl;
143
144                         NEXT_ARG();
145                         if (strcmp(*argv, "inherit") != 0) {
146                                 if (get_unsigned(&uval, *argv, 0))
147                                         invarg("invalid TTL\n", *argv);
148                                 if (uval > 255)
149                                         invarg("TTL must be <= 255\n", *argv);
150                                 ttl = uval;
151                                 addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
152                         }
153                 } else if (!matches(*argv, "tos") ||
154                            !matches(*argv, "tclass") ||
155                            !matches(*argv, "dsfield")) {
156                         __u32 uval;
157                         __u8 tos;
158
159                         NEXT_ARG();
160                         if (strcmp(*argv, "inherit") != 0) {
161                                 if (rtnl_dsfield_a2n(&uval, *argv))
162                                         invarg("bad TOS value", *argv);
163                                 tos = uval;
164                         } else
165                                 tos = 1;
166                         addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
167                 } else 
168                         usage();
169                 argc--; argv++;
170         }
171
172         if (!ikey && IN_MULTICAST(ntohl(daddr))) {
173                 ikey = daddr;
174                 iflags |= GRE_KEY;
175         }
176         if (!okey && IN_MULTICAST(ntohl(daddr))) {
177                 okey = daddr;
178                 oflags |= GRE_KEY;
179         }
180         if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
181                 fprintf(stderr, "Broadcast tunnel requires a source address.\n");
182                 return -1;
183         }
184
185         addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
186         addattr32(n, 1024, IFLA_GRE_OKEY, okey);
187         addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
188         addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
189         addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
190         addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
191
192         return 0;
193 }
194
195 static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
196 {
197         char s1[1024];
198         char s2[64];
199         const char *local = "any";
200         const char *remote = "any";
201         unsigned iflags = 0;
202         unsigned oflags = 0;
203
204         if (!tb)
205                 return;
206
207         if (tb[IFLA_GRE_REMOTE]) {
208                 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_REMOTE]);
209
210                 if (addr)
211                         remote = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
212         }
213
214         fprintf(f, "remote %s ", remote);
215
216         if (tb[IFLA_GRE_LOCAL]) {
217                 unsigned addr = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LOCAL]);
218
219                 if (addr)
220                         local = format_host(AF_INET, 4, &addr, s1, sizeof(s1));
221         }
222
223         fprintf(f, "local %s ", local);
224
225         if (tb[IFLA_GRE_LINK] && *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK])) {
226                 unsigned link = *(__u32 *)RTA_DATA(tb[IFLA_GRE_LINK]);
227                 char *n = tnl_ioctl_get_ifname(link);
228
229                 if (n)
230                         fprintf(f, "dev %s ", n);
231                 else
232                         fprintf(f, "dev %u ", link);
233         }
234
235         if (tb[IFLA_GRE_TTL] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]))
236                 fprintf(f, "ttl %d ", *(__u8 *)RTA_DATA(tb[IFLA_GRE_TTL]));
237         else
238                 fprintf(f, "ttl inherit ");
239
240         if (tb[IFLA_GRE_TOS] && *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS])) {
241                 int tos = *(__u8 *)RTA_DATA(tb[IFLA_GRE_TOS]);
242
243                 fputs("tos ", f);
244                 if (tos == 1)
245                         fputs("inherit ", f);
246                 else
247                         fprintf(f, "0x%x ", tos);
248         }
249
250         if (tb[IFLA_GRE_PMTUDISC] &&
251             !*(__u8 *)RTA_DATA(tb[IFLA_GRE_PMTUDISC]))
252                 fputs("nopmtudisc ", f);
253
254         if (tb[IFLA_GRE_IFLAGS])
255                 iflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_IFLAGS]);
256
257         if (tb[IFLA_GRE_OFLAGS])
258                 oflags = *(__u16 *)RTA_DATA(tb[IFLA_GRE_OFLAGS]);
259
260         if (iflags & GRE_KEY && tb[IFLA_GRE_IKEY] &&
261             *(__u32 *)RTA_DATA(tb[IFLA_GRE_IKEY])) {
262                 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
263                 fprintf(f, "ikey %s ", s2);
264         }
265
266         if (oflags & GRE_KEY && tb[IFLA_GRE_OKEY] &&
267             *(__u32 *)RTA_DATA(tb[IFLA_GRE_OKEY])) {
268                 inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
269                 fprintf(f, "ikey %s ", s2);
270         }
271
272         if (iflags & GRE_SEQ)
273                 fputs("iseq ", f);
274         if (oflags & GRE_SEQ)
275                 fputs("oseq ", f);
276         if (iflags & GRE_CSUM)
277                 fputs("icsum ", f);
278         if (oflags & GRE_CSUM)
279                 fputs("ocsum ", f);
280 }
281
282 struct link_util gre_link_util = {
283         .id = "gre",
284         .maxattr = IFLA_GRE_MAX,
285         .parse_opt = gre_parse_opt,
286         .print_opt = gre_print_opt,
287 };
288
289 struct link_util gretap_link_util = {
290         .id = "gretap",
291         .maxattr = IFLA_GRE_MAX,
292         .parse_opt = gre_parse_opt,
293         .print_opt = gre_print_opt,
294 };