~ubuntu-branches/ubuntu/quantal/iproute/quantal-proposed

« back to all changes in this revision

Viewing changes to ip/iproute.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Henriksson
  • Date: 2011-04-07 13:26:51 UTC
  • mfrom: (1.1.12 upstream) (23.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110407132651-oqhvd72lrcovuip4
Tags: 20110315-1
Imported Upstream version 2.6.38 (snapshot 20110315)

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
#include <netinet/ip.h>
24
24
#include <arpa/inet.h>
25
25
#include <linux/in_route.h>
 
26
#include <errno.h>
26
27
 
27
28
#include "rt_names.h"
28
29
#include "utils.h"
32
33
#define RTAX_RTTVAR RTAX_HOPS
33
34
#endif
34
35
 
35
 
 
 
36
enum list_action {
 
37
        IPROUTE_LIST,
 
38
        IPROUTE_FLUSH,
 
39
        IPROUTE_SAVE,
 
40
};
36
41
static const char *mx_names[RTAX_MAX+1] = {
37
42
        [RTAX_MTU]      = "mtu",
38
43
        [RTAX_WINDOW]   = "window",
53
58
static void usage(void)
54
59
{
55
60
        fprintf(stderr, "Usage: ip route { list | flush } SELECTOR\n");
 
61
        fprintf(stderr, "       ip route save SELECTOR\n");
 
62
        fprintf(stderr, "       ip route restore\n");
56
63
        fprintf(stderr, "       ip route get ADDRESS [ from ADDRESS iif STRING ]\n");
57
64
        fprintf(stderr, "                            [ oif STRING ]  [ tos TOS ]\n");
 
65
        fprintf(stderr, "                            [ mark NUMBER ]\n");
58
66
        fprintf(stderr, "       ip route { add | del | change | append | replace | monitor } ROUTE\n");
59
67
        fprintf(stderr, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n");
60
68
        fprintf(stderr, "            [ table TABLE_ID ] [ proto RTPROTO ]\n");
77
85
        fprintf(stderr, "MP_ALGO := { rr | drr | random | wrandom }\n");
78
86
        fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n");
79
87
        fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n");
80
 
        fprintf(stderr, "TIME := NUMBER[s|ms|us|ns|j]\n");
 
88
        fprintf(stderr, "TIME := NUMBER[s|ms]\n");
81
89
        exit(-1);
82
90
}
83
91
 
96
104
        int tos, tosmask;
97
105
        int iif, iifmask;
98
106
        int oif, oifmask;
 
107
        int mark, markmask;
99
108
        int realm, realmmask;
100
109
        inet_prefix rprefsrc;
101
110
        inet_prefix rvia;
115
124
        return 0;
116
125
}
117
126
 
118
 
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
127
int filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
119
128
{
120
 
        FILE *fp = (FILE*)arg;
121
129
        struct rtmsg *r = NLMSG_DATA(n);
122
 
        int len = n->nlmsg_len;
123
 
        struct rtattr * tb[RTA_MAX+1];
124
 
        char abuf[256];
125
130
        inet_prefix dst;
126
131
        inet_prefix src;
 
132
        inet_prefix via;
127
133
        inet_prefix prefsrc;
128
 
        inet_prefix via;
129
 
        int host_len = -1;
 
134
        __u32 table;
130
135
        static int ip6_multiple_tables;
131
 
        __u32 table;
132
 
        SPRINT_BUF(b1);
133
 
        static int hz;
134
 
 
135
 
        if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
136
 
                fprintf(stderr, "Not a route: %08x %08x %08x\n",
137
 
                        n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
138
 
                return 0;
139
 
        }
140
 
        if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
141
 
                return 0;
142
 
        len -= NLMSG_LENGTH(sizeof(*r));
143
 
        if (len < 0) {
144
 
                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
145
 
                return -1;
146
 
        }
147
 
 
148
 
        if (r->rtm_family == AF_INET6)
149
 
                host_len = 128;
150
 
        else if (r->rtm_family == AF_INET)
151
 
                host_len = 32;
152
 
        else if (r->rtm_family == AF_DECnet)
153
 
                host_len = 16;
154
 
        else if (r->rtm_family == AF_IPX)
155
 
                host_len = 80;
156
 
 
157
 
        parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
 
136
 
158
137
        table = rtm_get_table(r, tb);
159
138
 
160
139
        if (r->rtm_family == AF_INET6 && table != RT_TABLE_MAIN)
161
140
                ip6_multiple_tables = 1;
162
141
 
 
142
        if (filter.cloned == !(r->rtm_flags&RTM_F_CLONED))
 
143
                return 0;
 
144
 
163
145
        if (r->rtm_family == AF_INET6 && !ip6_multiple_tables) {
164
 
                if (filter.cloned) {
165
 
                        if (!(r->rtm_flags&RTM_F_CLONED))
166
 
                                return 0;
167
 
                }
168
146
                if (filter.tb) {
169
 
                        if (!filter.cloned && r->rtm_flags&RTM_F_CLONED)
170
 
                                return 0;
171
147
                        if (filter.tb == RT_TABLE_LOCAL) {
172
148
                                if (r->rtm_type != RTN_LOCAL)
173
149
                                        return 0;
179
155
                        }
180
156
                }
181
157
        } else {
182
 
                if (filter.cloned) {
183
 
                        if (!(r->rtm_flags&RTM_F_CLONED))
184
 
                                return 0;
185
 
                }
186
158
                if (filter.tb > 0 && filter.tb != table)
187
159
                        return 0;
188
160
        }
273
245
                if ((oif^filter.oif)&filter.oifmask)
274
246
                        return 0;
275
247
        }
 
248
        if (filter.markmask) {
 
249
                int mark = 0;
 
250
                if (tb[RTA_MARK])
 
251
                        mark = *(int *)RTA_DATA(tb[RTA_MARK]);
 
252
                if ((mark ^ filter.mark) & filter.markmask)
 
253
                        return 0;
 
254
        }
276
255
        if (filter.flushb &&
277
256
            r->rtm_family == AF_INET6 &&
278
257
            r->rtm_dst_len == 0 &&
281
260
            *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
282
261
                return 0;
283
262
 
 
263
        return 1;
 
264
}
 
265
 
 
266
int calc_host_len(struct rtmsg *r)
 
267
{
 
268
        if (r->rtm_family == AF_INET6)
 
269
                return 128;
 
270
        else if (r->rtm_family == AF_INET)
 
271
                return 32;
 
272
        else if (r->rtm_family == AF_DECnet)
 
273
                return 16;
 
274
        else if (r->rtm_family == AF_IPX)
 
275
                return 80;
 
276
        else
 
277
                return -1;
 
278
}
 
279
 
 
280
int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
281
{
 
282
        FILE *fp = (FILE*)arg;
 
283
        struct rtmsg *r = NLMSG_DATA(n);
 
284
        int len = n->nlmsg_len;
 
285
        struct rtattr * tb[RTA_MAX+1];
 
286
        char abuf[256];
 
287
        int host_len = -1;
 
288
        __u32 table;
 
289
        SPRINT_BUF(b1);
 
290
        static int hz;
 
291
 
 
292
        if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
 
293
                fprintf(stderr, "Not a route: %08x %08x %08x\n",
 
294
                        n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
 
295
                return 0;
 
296
        }
 
297
        if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
 
298
                return 0;
 
299
        len -= NLMSG_LENGTH(sizeof(*r));
 
300
        if (len < 0) {
 
301
                fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
 
302
                return -1;
 
303
        }
 
304
 
 
305
        host_len = calc_host_len(r);
 
306
 
 
307
        parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
 
308
        table = rtm_get_table(r, tb);
 
309
 
 
310
        if (!filter_nlmsg(n, tb, host_len))
 
311
                return 0;
 
312
 
284
313
        if (filter.flushb) {
285
314
                struct nlmsghdr *fn;
286
315
                if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
384
413
                fprintf(fp, "pervasive ");
385
414
        if (r->rtm_flags & RTM_F_NOTIFY)
386
415
                fprintf(fp, "notify ");
 
416
        if (tb[RTA_MARK]) {
 
417
                unsigned int mark = *(unsigned int*)RTA_DATA(tb[RTA_MARK]);
 
418
                if (mark) {
 
419
                        if (mark >= 16)
 
420
                                fprintf(fp, " mark 0x%x", mark);
 
421
                        else
 
422
                                fprintf(fp, " mark %u", mark);
 
423
                }
 
424
        }
387
425
 
388
426
        if (tb[RTA_FLOW] && filter.realmmask != ~0U) {
389
427
                __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
488
526
 
489
527
                        if (mxrta[i] == NULL)
490
528
                                continue;
491
 
                        if (!hz)
492
 
                                hz = get_hz();
493
529
 
494
530
                        if (i < sizeof(mx_names)/sizeof(char*) && mx_names[i])
495
531
                                fprintf(fp, " %s", mx_names[i]);
501
537
                        val = *(unsigned*)RTA_DATA(mxrta[i]);
502
538
                        switch (i) {
503
539
                        case RTAX_HOPLIMIT:
504
 
                                if ((long)val == -1)
 
540
                                if ((int)val == -1)
505
541
                                        val = 0;
506
542
                                /* fall through */
507
543
                        default:
511
547
                        case RTAX_RTT:
512
548
                        case RTAX_RTTVAR:
513
549
                        case RTAX_RTO_MIN:
514
 
                                val *= 1000;
515
550
                                if (i == RTAX_RTT)
516
551
                                        val /= 8;
517
552
                                else if (i == RTAX_RTTVAR)
518
553
                                        val /= 4;
519
554
 
520
 
                                if (val >= hz)
521
 
                                        fprintf(fp, " %llums",
522
 
                                                (unsigned long long) val / hz);
 
555
                                if (val >= 1000)
 
556
                                        fprintf(fp, " %gs", val/1e3);
523
557
                                else
524
 
                                        fprintf(fp, " %.2fms", 
525
 
                                                (double)val / hz);
 
558
                                        fprintf(fp, " %ums", val);
526
559
                        }
527
560
                }
528
561
        }
802
835
                                mxlock |= (1<<RTAX_RTT);
803
836
                                NEXT_ARG();
804
837
                        }
805
 
                        if (get_jiffies(&rtt, *argv, 0, &raw))
 
838
                        if (get_time_rtt(&rtt, *argv, &raw))
806
839
                                invarg("\"rtt\" value is invalid\n", *argv);
807
840
                        rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT, 
808
841
                                (raw) ? rtt : rtt * 8);
810
843
                        unsigned rto_min;
811
844
                        NEXT_ARG();
812
845
                        mxlock |= (1<<RTAX_RTO_MIN);
813
 
                        if (get_jiffies(&rto_min, *argv, 0, &raw))
 
846
                        if (get_time_rtt(&rto_min, *argv, &raw))
814
847
                                invarg("\"rto_min\" value is invalid\n",
815
848
                                       *argv);
816
849
                        rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTO_MIN,
862
895
                                mxlock |= (1<<RTAX_RTTVAR);
863
896
                                NEXT_ARG();
864
897
                        }
865
 
                        if (get_jiffies(&win, *argv, 0, &raw))
 
898
                        if (get_time_rtt(&win, *argv, &raw))
866
899
                                invarg("\"rttvar\" value is invalid\n", *argv);
867
900
                        rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR,
868
901
                                (raw) ? win : win * 4);
1041
1074
        return 0;
1042
1075
}
1043
1076
 
1044
 
 
1045
 
static int iproute_list_or_flush(int argc, char **argv, int flush)
 
1077
int save_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
1078
{
 
1079
        int ret;
 
1080
        int len = n->nlmsg_len;
 
1081
        struct rtmsg *r = NLMSG_DATA(n);
 
1082
        struct rtattr *tb[RTA_MAX+1];
 
1083
        int host_len = -1;
 
1084
 
 
1085
        if (isatty(STDOUT_FILENO)) {
 
1086
                fprintf(stderr, "Not sending binary stream to stdout\n");
 
1087
                return -1;
 
1088
        }
 
1089
 
 
1090
        host_len = calc_host_len(r);
 
1091
        len -= NLMSG_LENGTH(sizeof(*r));
 
1092
        parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
 
1093
 
 
1094
        if (!filter_nlmsg(n, tb, host_len))
 
1095
                return 0;
 
1096
 
 
1097
        ret = write(STDOUT_FILENO, n, n->nlmsg_len);
 
1098
        if ((ret > 0) && (ret != n->nlmsg_len)) {
 
1099
                fprintf(stderr, "Short write while saving nlmsg\n");
 
1100
                ret = -EIO;
 
1101
        }
 
1102
 
 
1103
        return ret == n->nlmsg_len ? 0 : ret;
 
1104
}
 
1105
 
 
1106
static int iproute_list_flush_or_save(int argc, char **argv, int action)
1046
1107
{
1047
1108
        int do_ipv6 = preferred_family;
1048
1109
        char *id = NULL;
1049
1110
        char *od = NULL;
 
1111
        unsigned int mark = 0;
 
1112
        rtnl_filter_t filter_fn;
 
1113
 
 
1114
        if (action == IPROUTE_SAVE)
 
1115
                filter_fn = save_route;
 
1116
        else
 
1117
                filter_fn = print_route;
1050
1118
 
1051
1119
        iproute_reset_filter();
1052
1120
        filter.tb = RT_TABLE_MAIN;
1053
1121
 
1054
 
        if (flush && argc <= 0) {
 
1122
        if ((action == IPROUTE_FLUSH) && argc <= 0) {
1055
1123
                fprintf(stderr, "\"ip route flush\" requires arguments.\n");
1056
1124
                return -1;
1057
1125
        }
1119
1187
                } else if (strcmp(*argv, "iif") == 0) {
1120
1188
                        NEXT_ARG();
1121
1189
                        id = *argv;
 
1190
                } else if (strcmp(*argv, "mark") == 0) {
 
1191
                        NEXT_ARG();
 
1192
                        get_unsigned(&mark, *argv, 0);
 
1193
                        filter.markmask = -1;
1122
1194
                } else if (strcmp(*argv, "via") == 0) {
1123
1195
                        NEXT_ARG();
1124
1196
                        get_prefix(&filter.rvia, *argv, do_ipv6);
1200
1272
                        filter.oifmask = -1;
1201
1273
                }
1202
1274
        }
 
1275
        filter.mark = mark;
1203
1276
 
1204
 
        if (flush) {
 
1277
        if (action == IPROUTE_FLUSH) {
1205
1278
                int round = 0;
1206
1279
                char flushb[4096-512];
1207
1280
                time_t start = time(0);
1226
1299
                                exit(1);
1227
1300
                        }
1228
1301
                        filter.flushed = 0;
1229
 
                        if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
 
1302
                        if (rtnl_dump_filter(&rth, filter_fn, stdout, NULL, NULL) < 0) {
1230
1303
                                fprintf(stderr, "Flush terminated\n");
1231
1304
                                exit(1);
1232
1305
                        }
1269
1342
                }
1270
1343
        }
1271
1344
 
1272
 
        if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
 
1345
        if (rtnl_dump_filter(&rth, filter_fn, stdout, NULL, NULL) < 0) {
1273
1346
                fprintf(stderr, "Dump terminated\n");
1274
1347
                exit(1);
1275
1348
        }
1289
1362
        char  *odev = NULL;
1290
1363
        int connected = 0;
1291
1364
        int from_ok = 0;
 
1365
        unsigned int mark = 0;
1292
1366
 
1293
1367
        memset(&req, 0, sizeof(req));
1294
1368
 
1295
1369
        iproute_reset_filter();
 
1370
        filter.cloned = 2;
1296
1371
 
1297
1372
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
1298
1373
        req.n.nlmsg_flags = NLM_F_REQUEST;
1329
1404
                } else if (matches(*argv, "iif") == 0) {
1330
1405
                        NEXT_ARG();
1331
1406
                        idev = *argv;
 
1407
                } else if (matches(*argv, "mark") == 0) {
 
1408
                        NEXT_ARG();
 
1409
                        get_unsigned(&mark, *argv, 0);
1332
1410
                } else if (matches(*argv, "oif") == 0 ||
1333
1411
                           strcmp(*argv, "dev") == 0) {
1334
1412
                        NEXT_ARG();
1379
1457
                        addattr32(&req.n, sizeof(req), RTA_OIF, idx);
1380
1458
                }
1381
1459
        }
 
1460
        if (mark)
 
1461
                addattr32(&req.n, sizeof(req), RTA_MARK, mark);
1382
1462
 
1383
1463
        if (req.r.rtm_family == AF_UNSPEC)
1384
1464
                req.r.rtm_family = AF_INET;
1436
1516
        exit(0);
1437
1517
}
1438
1518
 
 
1519
int restore_handler(const struct sockaddr_nl *nl, struct nlmsghdr *n, void *arg)
 
1520
{
 
1521
        int ret;
 
1522
 
 
1523
        n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
 
1524
 
 
1525
        ll_init_map(&rth);
 
1526
 
 
1527
        ret = rtnl_talk(&rth, n, 0, 0, n, NULL, NULL);
 
1528
        if ((ret < 0) && (errno == EEXIST))
 
1529
                ret = 0;
 
1530
 
 
1531
        return ret;
 
1532
}
 
1533
 
 
1534
int iproute_restore(void)
 
1535
{
 
1536
        exit(rtnl_from_file(stdin, &restore_handler, NULL));
 
1537
}
 
1538
 
1439
1539
void iproute_reset_filter()
1440
1540
{
1441
1541
        memset(&filter, 0, sizeof(filter));
1446
1546
int do_iproute(int argc, char **argv)
1447
1547
{
1448
1548
        if (argc < 1)
1449
 
                return iproute_list_or_flush(0, NULL, 0);
 
1549
                return iproute_list_flush_or_save(0, NULL, IPROUTE_LIST);
1450
1550
 
1451
1551
        if (matches(*argv, "add") == 0)
1452
1552
                return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL,
1471
1571
                                      argc-1, argv+1);
1472
1572
        if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0
1473
1573
            || matches(*argv, "lst") == 0)
1474
 
                return iproute_list_or_flush(argc-1, argv+1, 0);
 
1574
                return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_LIST);
1475
1575
        if (matches(*argv, "get") == 0)
1476
1576
                return iproute_get(argc-1, argv+1);
1477
1577
        if (matches(*argv, "flush") == 0)
1478
 
                return iproute_list_or_flush(argc-1, argv+1, 1);
 
1578
                return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_FLUSH);
 
1579
        if (matches(*argv, "save") == 0)
 
1580
                return iproute_list_flush_or_save(argc-1, argv+1, IPROUTE_SAVE);
 
1581
        if (matches(*argv, "restore") == 0)
 
1582
                return iproute_restore();
1479
1583
        if (matches(*argv, "help") == 0)
1480
1584
                usage();
1481
1585
        fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv);