~ubuntu-branches/ubuntu/karmic/iproute/karmic

« back to all changes in this revision

Viewing changes to ip/link_gre.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Henriksson
  • Date: 2009-03-26 12:36:10 UTC
  • mfrom: (1.1.8 upstream) (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090326123610-00avh089ttrj5bsg
Tags: 20090324-1
* New upstream release v2.6.29-1 (includes "Fix headers needed for gre")
  - fixed to link against xtables rather then ipt. (Closes: #510924)
* Make sure clean drops any potential left-over files from WRR qdisc patch.
* Bump standards version to policy 3.8.1, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 = 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
 
 
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
};