]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/link_gre.c
netem: add support for 4 state and GE loss model
[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 <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));
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
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 = if_nametoindex(*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
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                 const char *n = if_indextoname(link, s2);
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 };