~ubuntu-branches/ubuntu/precise/iproute/precise

« back to all changes in this revision

Viewing changes to ip/ip6tunnel.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio M. Di Nitto
  • Date: 2007-06-11 13:31:12 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070611133112-0rtfv32yfs8loo0r
Tags: 20070313-1ubuntu1
* Merge from debian unstable, remaining changes:
  - linux-kernel-headers -> linux-libc-dev B-D rename.
  - MAX_ROUNDS patch to ip/ipaddress.c
  - Ubuntu maintainer foobar.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C)2006 USAGI/WIDE Project
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 */
 
18
/*
 
19
 * based on:
 
20
 * $Id: s.ipv6tunnel.c 1.7 02/12/11 11:21:51+02:00 antti@traci.mipl.mediapoli.com $
 
21
 *
 
22
 */
 
23
/*
 
24
 * Author:
 
25
 *      Masahide NAKAMURA @USAGI
 
26
 */
 
27
 
 
28
#include <stdio.h>
 
29
#include <string.h>
 
30
#include <stdlib.h>
 
31
#include <unistd.h>
 
32
#include <sys/types.h>
 
33
#include <sys/socket.h>
 
34
#include <arpa/inet.h>
 
35
#include <sys/ioctl.h>
 
36
#include <linux/ip.h>
 
37
#include <linux/if.h>
 
38
#include <linux/if_arp.h>
 
39
#include <linux/if_tunnel.h>
 
40
#include <linux/ip6_tunnel.h>
 
41
 
 
42
#include "utils.h"
 
43
#include "tunnel.h"
 
44
 
 
45
#define IP6_FLOWINFO_TCLASS     htonl(0x0FF00000)
 
46
#define IP6_FLOWINFO_FLOWLABEL  htonl(0x000FFFFF)
 
47
 
 
48
#define DEFAULT_TNL_HOP_LIMIT   (64)
 
49
 
 
50
static void usage(void) __attribute__((noreturn));
 
51
 
 
52
static void usage(void)
 
53
{
 
54
        fprintf(stderr, "Usage: ip -f inet6 tunnel { add | change | del | show } [ NAME ]\n");
 
55
        fprintf(stderr, "          [ remote ADDR local ADDR ] [ dev PHYS_DEV ]\n");
 
56
        fprintf(stderr, "          [ encaplimit ELIM ]\n");
 
57
        fprintf(stderr ,"          [ hoplimit HLIM ] [ tc TC ] [ fl FL ]\n");
 
58
        fprintf(stderr, "          [ dscp inherit ]\n");
 
59
        fprintf(stderr, "\n");
 
60
        fprintf(stderr, "Where: NAME := STRING\n");
 
61
        fprintf(stderr, "       ADDR := IPV6_ADDRESS\n");
 
62
        fprintf(stderr, "       ELIM := { none | 0..255 }(default=%d)\n",
 
63
                IPV6_DEFAULT_TNL_ENCAP_LIMIT);
 
64
        fprintf(stderr, "       HLIM := 0..255 (default=%d)\n",
 
65
                DEFAULT_TNL_HOP_LIMIT);
 
66
        fprintf(stderr, "       TC   := { 0x0..0xff | inherit }\n");
 
67
        fprintf(stderr, "       FL   := { 0x0..0xfffff | inherit }\n");
 
68
        exit(-1);
 
69
}
 
70
 
 
71
static void print_tunnel(struct ip6_tnl_parm *p)
 
72
{
 
73
        char remote[64];
 
74
        char local[64];
 
75
 
 
76
        inet_ntop(AF_INET6, &p->raddr, remote, sizeof(remote));
 
77
        inet_ntop(AF_INET6, &p->laddr, local, sizeof(local));
 
78
 
 
79
        printf("%s: %s/ipv6 remote %s local %s",
 
80
               p->name, tnl_strproto(p->proto), remote, local);
 
81
        if (p->link) {
 
82
                char *n = tnl_ioctl_get_ifname(p->link);
 
83
                if (n)
 
84
                        printf(" dev %s", n);
 
85
        }
 
86
 
 
87
        if (p->flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
 
88
                printf(" encaplimit none");
 
89
        else
 
90
                printf(" encaplimit %u", p->encap_limit);
 
91
 
 
92
        printf(" hoplimit %u", p->hop_limit);
 
93
 
 
94
        if (p->flags & IP6_TNL_F_USE_ORIG_TCLASS)
 
95
                printf(" tc inherit");
 
96
        else {
 
97
                __u32 val = ntohl(p->flowinfo & IP6_FLOWINFO_TCLASS);
 
98
                printf(" tc 0x%02x", (__u8)(val >> 20));
 
99
        }
 
100
 
 
101
        if (p->flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
 
102
                printf(" fl inherit");
 
103
        else
 
104
                printf(" fl 0x%05x", ntohl(p->flowinfo & IP6_FLOWINFO_FLOWLABEL));
 
105
 
 
106
        printf(" (flowinfo 0x%08x)", ntohl(p->flowinfo));
 
107
 
 
108
        if (p->flags & IP6_TNL_F_RCV_DSCP_COPY)
 
109
                printf(" dscp inherit");
 
110
}
 
111
 
 
112
static int parse_args(int argc, char **argv, struct ip6_tnl_parm *p)
 
113
{
 
114
        char medium[IFNAMSIZ];
 
115
 
 
116
        memset(medium, 0, sizeof(medium));
 
117
 
 
118
        while (argc > 0) {
 
119
                if (strcmp(*argv, "remote") == 0) {
 
120
                        inet_prefix raddr;
 
121
                        NEXT_ARG();
 
122
                        get_prefix(&raddr, *argv, preferred_family);
 
123
                        if (raddr.family == AF_UNSPEC)
 
124
                                invarg("\"remote\" address family is AF_UNSPEC", *argv);
 
125
                        memcpy(&p->raddr, &raddr.data, sizeof(p->raddr));
 
126
                } else if (strcmp(*argv, "local") == 0) {
 
127
                        inet_prefix laddr;
 
128
                        NEXT_ARG();
 
129
                        get_prefix(&laddr, *argv, preferred_family);
 
130
                        if (laddr.family == AF_UNSPEC)
 
131
                                invarg("\"local\" address family is AF_UNSPEC", *argv);
 
132
                        memcpy(&p->laddr, &laddr.data, sizeof(p->laddr));
 
133
                } else if (strcmp(*argv, "dev") == 0) {
 
134
                        NEXT_ARG();
 
135
                        strncpy(medium, *argv, IFNAMSIZ - 1);
 
136
                } else if (strcmp(*argv, "encaplimit") == 0) {
 
137
                        NEXT_ARG();
 
138
                        if (strcmp(*argv, "none") == 0) {
 
139
                                p->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
 
140
                        } else {
 
141
                                __u8 uval;
 
142
                                if (get_u8(&uval, *argv, 0) < -1)
 
143
                                        invarg("invalid ELIM", *argv);
 
144
                                p->encap_limit = uval;
 
145
                        }
 
146
                } else if (strcmp(*argv, "hoplimit") == 0) {
 
147
                        __u8 uval;
 
148
                        NEXT_ARG();
 
149
                        if (get_u8(&uval, *argv, 0))
 
150
                                invarg("invalid HLIM", *argv);
 
151
                        p->hop_limit = uval;
 
152
                } else if (strcmp(*argv, "tc") == 0) {
 
153
                        __u8 uval;
 
154
                        NEXT_ARG();
 
155
                        if (strcmp(*argv, "inherit") == 0)
 
156
                                p->flags |= IP6_TNL_F_USE_ORIG_TCLASS;
 
157
                        else {
 
158
                                if (get_u8(&uval, *argv, 16))
 
159
                                        invarg("invalid TC", *argv);
 
160
                                p->flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
 
161
                                p->flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
 
162
                        }
 
163
                } else if (strcmp(*argv, "fl") == 0) {
 
164
                        __u32 uval;
 
165
                        NEXT_ARG();
 
166
                        if (strcmp(*argv, "inherit") == 0)
 
167
                                p->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
 
168
                        else {
 
169
                                if (get_u32(&uval, *argv, 16))
 
170
                                        invarg("invalid FL", *argv);
 
171
                                if (uval > 0xFFFFF)
 
172
                                        invarg("invalid FL", *argv);
 
173
                                p->flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
 
174
                                p->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
 
175
                        }
 
176
                } else if (strcmp(*argv, "dscp") == 0) {
 
177
                        NEXT_ARG();
 
178
                        if (strcmp(*argv, "inherit") != 0)
 
179
                                invarg("not inherit", *argv);
 
180
                        p->flags |= IP6_TNL_F_RCV_DSCP_COPY;
 
181
                } else {
 
182
                        if (strcmp(*argv, "name") == 0) {
 
183
                                NEXT_ARG();
 
184
                        }
 
185
                        if (matches(*argv, "help") == 0)
 
186
                                usage();
 
187
                        if (p->name[0])
 
188
                                duparg2("name", *argv);
 
189
                        strncpy(p->name, *argv, IFNAMSIZ - 1);
 
190
                }
 
191
                argc--; argv++;
 
192
        }
 
193
        if (medium[0]) {
 
194
                p->link = tnl_ioctl_get_ifindex(medium);
 
195
                if (p->link == 0)
 
196
                        return -1;
 
197
        }
 
198
        return 0;
 
199
}
 
200
 
 
201
static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
 
202
{
 
203
        memset(p, 0, sizeof(*p));
 
204
        p->proto = IPPROTO_IPV6;
 
205
        if (apply_default) {
 
206
                p->hop_limit = DEFAULT_TNL_HOP_LIMIT;
 
207
                p->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
 
208
        }
 
209
}
 
210
 
 
211
/*
 
212
 * @p1: user specified parameter
 
213
 * @p2: database entry
 
214
 */
 
215
static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
 
216
                              const struct ip6_tnl_parm *p2)
 
217
{
 
218
        return ((!p1->link || p1->link == p2->link) &&
 
219
                (!p1->name[0] || strcmp(p1->name, p2->name) == 0) &&
 
220
                (memcmp(&p1->laddr, &in6addr_any, sizeof(p1->laddr)) == 0 ||
 
221
                 memcmp(&p1->laddr, &p2->laddr, sizeof(p1->laddr)) == 0) &&
 
222
                (memcmp(&p1->raddr, &in6addr_any, sizeof(p1->raddr)) == 0 ||
 
223
                 memcmp(&p1->raddr, &p2->raddr, sizeof(p1->raddr)) == 0) &&
 
224
                (!p1->proto || !p2->proto || p1->proto == p2->proto) &&
 
225
                (!p1->encap_limit || p1->encap_limit == p2->encap_limit) &&
 
226
                (!p1->hop_limit || p1->hop_limit == p2->hop_limit) &&
 
227
                (!(p1->flowinfo & IP6_FLOWINFO_TCLASS) ||
 
228
                 !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_TCLASS)) &&
 
229
                (!(p1->flowinfo & IP6_FLOWINFO_FLOWLABEL) ||
 
230
                 !((p1->flowinfo ^ p2->flowinfo) & IP6_FLOWINFO_FLOWLABEL)) &&
 
231
                (!p1->flags || (p1->flags & p2->flags)));
 
232
}
 
233
 
 
234
static int do_tunnels_list(struct ip6_tnl_parm *p)
 
235
{
 
236
        char buf[512];
 
237
        int err = -1;
 
238
        FILE *fp = fopen("/proc/net/dev", "r");
 
239
        if (fp == NULL) {
 
240
                perror("fopen");
 
241
                goto end;
 
242
        }
 
243
 
 
244
        /* skip two lines at the begenning of the file */
 
245
        fgets(buf, sizeof(buf), fp);
 
246
        fgets(buf, sizeof(buf), fp);
 
247
 
 
248
        while (fgets(buf, sizeof(buf), fp) != NULL) {
 
249
                char name[IFNAMSIZ];
 
250
                int type;
 
251
                unsigned long rx_bytes, rx_packets, rx_errs, rx_drops,
 
252
                        rx_fifo, rx_frame,
 
253
                        tx_bytes, tx_packets, tx_errs, tx_drops,
 
254
                        tx_fifo, tx_colls, tx_carrier, rx_multi;
 
255
                struct ip6_tnl_parm p1;
 
256
                char *ptr;
 
257
 
 
258
                buf[sizeof(buf) - 1] = '\0';
 
259
                if ((ptr = strchr(buf, ':')) == NULL ||
 
260
                    (*ptr++ = 0, sscanf(buf, "%s", name) != 1)) {
 
261
                        fprintf(stderr, "Wrong format of /proc/net/dev. Sorry.\n");
 
262
                        goto end;
 
263
                }
 
264
                if (sscanf(ptr, "%ld%ld%ld%ld%ld%ld%ld%*d%ld%ld%ld%ld%ld%ld%ld",
 
265
                           &rx_bytes, &rx_packets, &rx_errs, &rx_drops,
 
266
                           &rx_fifo, &rx_frame, &rx_multi,
 
267
                           &tx_bytes, &tx_packets, &tx_errs, &tx_drops,
 
268
                           &tx_fifo, &tx_colls, &tx_carrier) != 14)
 
269
                        continue;
 
270
                if (p->name[0] && strcmp(p->name, name))
 
271
                        continue;
 
272
                type = tnl_ioctl_get_iftype(name);
 
273
                if (type == -1) {
 
274
                        fprintf(stderr, "Failed to get type of [%s]\n", name);
 
275
                        continue;
 
276
                }
 
277
                if (type != ARPHRD_TUNNEL6)
 
278
                        continue;
 
279
                memset(&p1, 0, sizeof(p1));
 
280
                ip6_tnl_parm_init(&p1, 0);
 
281
                strcpy(p1.name, name);
 
282
                p1.link = tnl_ioctl_get_ifindex(p1.name);
 
283
                if (p1.link == 0)
 
284
                        continue;
 
285
                if (tnl_get_ioctl(p1.name, &p1))
 
286
                        continue;
 
287
                if (!ip6_tnl_parm_match(p, &p1))
 
288
                        continue;
 
289
                print_tunnel(&p1);
 
290
                if (show_stats) {
 
291
                        printf("%s", _SL_);
 
292
                        printf("RX: Packets    Bytes        Errors CsumErrs OutOfSeq Mcasts%s", _SL_);
 
293
                        printf("    %-10ld %-12ld %-6ld %-8ld %-8ld %-8ld%s",
 
294
                               rx_packets, rx_bytes, rx_errs, rx_frame, rx_fifo, rx_multi, _SL_);
 
295
                        printf("TX: Packets    Bytes        Errors DeadLoop NoRoute  NoBufs%s", _SL_);
 
296
                        printf("    %-10ld %-12ld %-6ld %-8ld %-8ld %-6ld",
 
297
                               tx_packets, tx_bytes, tx_errs, tx_colls, tx_carrier, tx_drops);
 
298
                }
 
299
                printf("\n");
 
300
        }
 
301
        err = 0;
 
302
 
 
303
 end:
 
304
        if (fp)
 
305
                fclose(fp);
 
306
        return err;
 
307
}
 
308
 
 
309
static int do_show(int argc, char **argv)
 
310
{
 
311
        struct ip6_tnl_parm p;
 
312
 
 
313
        ip6_tnl_parm_init(&p, 0);
 
314
 
 
315
        if (parse_args(argc, argv, &p) < 0)
 
316
                return -1;
 
317
 
 
318
        if (!p.name[0] || show_stats)
 
319
                do_tunnels_list(&p);
 
320
        else {
 
321
                if (tnl_get_ioctl(p.name, &p))
 
322
                        return -1;
 
323
                print_tunnel(&p);
 
324
                printf("\n");
 
325
        }
 
326
 
 
327
        return 0;
 
328
}
 
329
 
 
330
static int do_add(int cmd, int argc, char **argv)
 
331
{
 
332
        struct ip6_tnl_parm p;
 
333
 
 
334
        ip6_tnl_parm_init(&p, 1);
 
335
 
 
336
        if (parse_args(argc, argv, &p) < 0)
 
337
                return -1;
 
338
 
 
339
        return tnl_add_ioctl(cmd,
 
340
                             cmd == SIOCCHGTUNNEL && p.name[0] ?
 
341
                             p.name : "ip6tnl0", p.name, &p);
 
342
}
 
343
 
 
344
static int do_del(int argc, char **argv)
 
345
{
 
346
        struct ip6_tnl_parm p;
 
347
 
 
348
        ip6_tnl_parm_init(&p, 1);
 
349
 
 
350
        if (parse_args(argc, argv, &p) < 0)
 
351
                return -1;
 
352
 
 
353
        return tnl_del_ioctl(p.name[0] ? p.name : "ip6tnl0", p.name, &p);
 
354
}
 
355
 
 
356
int do_ip6tunnel(int argc, char **argv)
 
357
{
 
358
        switch (preferred_family) {
 
359
        case AF_UNSPEC:
 
360
                preferred_family = AF_INET6;
 
361
                break;
 
362
        case AF_INET6:
 
363
                break;
 
364
        default:
 
365
                fprintf(stderr, "Unsupported family:%d\n", preferred_family);
 
366
                exit(-1);
 
367
        }
 
368
 
 
369
        if (argc > 0) {
 
370
                if (matches(*argv, "add") == 0)
 
371
                        return do_add(SIOCADDTUNNEL, argc - 1, argv + 1);
 
372
                if (matches(*argv, "change") == 0)
 
373
                        return do_add(SIOCCHGTUNNEL, argc - 1, argv + 1);
 
374
                if (matches(*argv, "del") == 0)
 
375
                        return do_del(argc - 1, argv + 1);
 
376
                if (matches(*argv, "show") == 0 ||
 
377
                    matches(*argv, "lst") == 0 ||
 
378
                    matches(*argv, "list") == 0)
 
379
                        return do_show(argc - 1, argv + 1);
 
380
                if (matches(*argv, "help") == 0)
 
381
                        usage();
 
382
        } else
 
383
                return do_show(0, NULL);
 
384
 
 
385
        fprintf(stderr, "Command \"%s\" is unknown, try \"ip -f inet6 tunnel help\".\n", *argv);
 
386
        exit(-1);
 
387
}