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

« back to all changes in this revision

Viewing changes to ip/iplink.c

  • Committer: Bazaar Package Importer
  • Author(s): Alexander Wirt, Andreas Henriksson, Ben Finney, Justin Pryzby, Daniel Silverstone, Alexander Wirt
  • Date: 2007-12-16 14:30:31 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20071216143031-cbd111kybw3o9mpv
Tags: 20071016-1
[ Andreas Henriksson ]
* New upstream release (v2.6.23 aka snapshot 071016) (Closes: #445944)
  - time2tick overflow patch applied upstream (Closes: #175462)
  - tc ematch cmp/nbyte help patch applied upstream (Closes: #438653)
  - mpath support dropped upstream (Closes: #428440, #428442)
  - new manpages included upstream (Closes: #438994)
  - linux header files updated to v2.6.23 (Closes: #409047)
* Drop patches which has been applied upstream or deprecated by
  upstream changes.
  - debian/patches/lartc applied upstream.
  - debian/patches/netbug_fix deprecated, upstream dropped netbug script.
  - debian/patches/empty_linkname.dpatch deprecated, fixed upstream.
* Add .dpatch suffix to wrr-qdisc patch to make dpatch-edit-patch work.
* Update patches to apply:
  - wrr-qdisc, moo, ip_route_usage
* Don't install removed netbug script.
* Fix corruption when using batch files with comments and broken
  lines. (cherry-picked from upstream. Closes: #398912)
* Update build-dependencies:
  - libdb4.3-dev -> libdb-dev. (Closes: #442653)
  - linux-kernel-headers -> linux-libc-dev.
* Drop debian/patches/ip_address_flush_loop.dpatch,
  instead we'll use Daniel Silverstones patch imported from Ubuntu.
* Add Homepage and Vcs-{Browser,Git} fields to debian/control.
* Remove dead/leftover code from tc/q_htb.c, include/linux/pkt_sched.h
* Remove outdated README.Debian.
* Drop our own (buggy) RTAX_INITCWND support, in favor of upstreams.
* fix dotted-quad support patch to work on big-endian.
  (upstream applied a broken patch, which we cherry-picked for #357172)

[ Ben Finney ]
* Add dh_md5sums to generate md5sums control file (Closes: #439439)

[ Justin Pryzby ]
* ss(8) manpage formatting breaks EXAMPLE (Closes: #443071)

[ Daniel Silverstone ]
* Avoid infinite loop in ip addr flush.

[ Alexander Wirt ]
* Add Andreas Henriksson to uploaders
* Bump standards version
* Support dotted-quad netmasks in iproute (Closes: #357172) (Cherry picked
  from upstream)

Show diffs side-by-side

added added

removed removed

Lines of Context:
15
15
#include <unistd.h>
16
16
#include <syslog.h>
17
17
#include <fcntl.h>
 
18
#include <dlfcn.h>
18
19
#include <errno.h>
19
20
#include <sys/socket.h>
20
21
#include <linux/if.h>
31
32
#include "utils.h"
32
33
#include "ip_common.h"
33
34
 
 
35
#define IPLINK_IOCTL_COMPAT     1
34
36
 
35
37
static void usage(void) __attribute__((noreturn));
36
38
 
62
64
        return -1;
63
65
}
64
66
 
 
67
static void *BODY;              /* cached dlopen(NULL) handle */
 
68
static struct link_util *linkutil_list;
 
69
 
 
70
struct link_util *get_link_kind(const char *id)
 
71
{
 
72
        void *dlh;
 
73
        char buf[256];
 
74
        struct link_util *l;
 
75
 
 
76
        for (l = linkutil_list; l; l = l->next)
 
77
                if (strcmp(l->id, id) == 0)
 
78
                        return l;
 
79
 
 
80
        snprintf(buf, sizeof(buf), "/usr/lib/ip/link_%s.so", id);
 
81
        dlh = dlopen(buf, RTLD_LAZY);
 
82
        if (dlh == NULL) {
 
83
                /* look in current binary, only open once */
 
84
                dlh = BODY;
 
85
                if (dlh == NULL) {
 
86
                        dlh = BODY = dlopen(NULL, RTLD_LAZY);
 
87
                        if (dlh == NULL)
 
88
                                return NULL;
 
89
                }
 
90
        }
 
91
 
 
92
        snprintf(buf, sizeof(buf), "%s_link_util", id);
 
93
        l = dlsym(dlh, buf);
 
94
        if (l == NULL)
 
95
                return NULL;
 
96
 
 
97
        l->next = linkutil_list;
 
98
        linkutil_list = l;
 
99
        return l;
 
100
}
 
101
 
 
102
#if IPLINK_IOCTL_COMPAT
 
103
static int have_rtnl_newlink = -1;
 
104
 
 
105
static int accept_msg(const struct sockaddr_nl *who,
 
106
                      struct nlmsghdr *n, void *arg)
 
107
{
 
108
        struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
 
109
 
 
110
        if (n->nlmsg_type == NLMSG_ERROR && err->error == -EOPNOTSUPP)
 
111
                have_rtnl_newlink = 0;
 
112
        else
 
113
                have_rtnl_newlink = 1;
 
114
        return -1;
 
115
}
 
116
 
 
117
static int iplink_have_newlink(void)
 
118
{
 
119
        struct {
 
120
                struct nlmsghdr         n;
 
121
                struct ifinfomsg        i;
 
122
                char                    buf[1024];
 
123
        } req;
 
124
 
 
125
        if (have_rtnl_newlink < 0) {
 
126
                memset(&req, 0, sizeof(req));
 
127
 
 
128
                req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
 
129
                req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
 
130
                req.n.nlmsg_type = RTM_NEWLINK;
 
131
                req.i.ifi_family = AF_UNSPEC;
 
132
 
 
133
                rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len);
 
134
                rtnl_listen(&rth, accept_msg, NULL);
 
135
        }
 
136
        return have_rtnl_newlink;
 
137
}
 
138
#else /* IPLINK_IOCTL_COMPAT */
 
139
static int iplink_have_newlink(void)
 
140
{
 
141
        return 1;
 
142
}
 
143
#endif /* ! IPLINK_IOCTL_COMPAT */
 
144
 
 
145
static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
 
146
{
 
147
        int qlen = -1;
 
148
        int mtu = -1;
 
149
        int len;
 
150
        char abuf[32];
 
151
        char *dev = NULL;
 
152
        char *name = NULL;
 
153
        char *link = NULL;
 
154
        char *type = NULL;
 
155
        struct link_util *lu = NULL;
 
156
        struct {
 
157
                struct nlmsghdr         n;
 
158
                struct ifinfomsg        i;
 
159
                char                    buf[1024];
 
160
        } req;
 
161
 
 
162
        memset(&req, 0, sizeof(req));
 
163
 
 
164
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
 
165
        req.n.nlmsg_flags = NLM_F_REQUEST|flags;
 
166
        req.n.nlmsg_type = cmd;
 
167
        req.i.ifi_family = preferred_family;
 
168
 
 
169
        while (argc > 0) {
 
170
                if (strcmp(*argv, "up") == 0) {
 
171
                        req.i.ifi_change |= IFF_UP;
 
172
                        req.i.ifi_flags |= IFF_UP;
 
173
                } else if (strcmp(*argv, "down") == 0) {
 
174
                        req.i.ifi_change |= IFF_UP;
 
175
                        req.i.ifi_flags &= ~IFF_UP;
 
176
                } else if (strcmp(*argv, "name") == 0) {
 
177
                        NEXT_ARG();
 
178
                        name = *argv;
 
179
                } else if (matches(*argv, "link") == 0) {
 
180
                        NEXT_ARG();
 
181
                        link = *argv;
 
182
                } else if (matches(*argv, "address") == 0) {
 
183
                        NEXT_ARG();
 
184
                        len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
 
185
                        addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len);
 
186
                } else if (matches(*argv, "broadcast") == 0 ||
 
187
                           strcmp(*argv, "brd") == 0) {
 
188
                        NEXT_ARG();
 
189
                        len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
 
190
                        addattr_l(&req.n, sizeof(req), IFLA_BROADCAST, abuf, len);
 
191
                } else if (matches(*argv, "txqueuelen") == 0 ||
 
192
                           strcmp(*argv, "qlen") == 0 ||
 
193
                           matches(*argv, "txqlen") == 0) {
 
194
                        NEXT_ARG();
 
195
                        if (qlen != -1)
 
196
                                duparg("txqueuelen", *argv);
 
197
                        if (get_integer(&qlen,  *argv, 0))
 
198
                                invarg("Invalid \"txqueuelen\" value\n", *argv);
 
199
                        addattr_l(&req.n, sizeof(req), IFLA_TXQLEN, &qlen, 4);
 
200
                } else if (strcmp(*argv, "mtu") == 0) {
 
201
                        NEXT_ARG();
 
202
                        if (mtu != -1)
 
203
                                duparg("mtu", *argv);
 
204
                        if (get_integer(&mtu, *argv, 0))
 
205
                                invarg("Invalid \"mtu\" value\n", *argv);
 
206
                        addattr_l(&req.n, sizeof(req), IFLA_MTU, &mtu, 4);
 
207
                } else if (strcmp(*argv, "multicast") == 0) {
 
208
                        NEXT_ARG();
 
209
                        req.i.ifi_change |= IFF_MULTICAST;
 
210
                        if (strcmp(*argv, "on") == 0) {
 
211
                                req.i.ifi_flags |= IFF_MULTICAST;
 
212
                        } else if (strcmp(*argv, "off") == 0) {
 
213
                                req.i.ifi_flags &= ~IFF_MULTICAST;
 
214
                        } else
 
215
                                return on_off("multicast");
 
216
                } else if (strcmp(*argv, "allmulticast") == 0) {
 
217
                        NEXT_ARG();
 
218
                        req.i.ifi_change |= IFF_ALLMULTI;
 
219
                        if (strcmp(*argv, "on") == 0) {
 
220
                                req.i.ifi_flags |= IFF_ALLMULTI;
 
221
                        } else if (strcmp(*argv, "off") == 0) {
 
222
                                req.i.ifi_flags &= ~IFF_ALLMULTI;
 
223
                        } else
 
224
                                return on_off("allmulticast");
 
225
                } else if (strcmp(*argv, "promisc") == 0) {
 
226
                        NEXT_ARG();
 
227
                        req.i.ifi_change |= IFF_PROMISC;
 
228
                        if (strcmp(*argv, "on") == 0) {
 
229
                                req.i.ifi_flags |= IFF_PROMISC;
 
230
                        } else if (strcmp(*argv, "off") == 0) {
 
231
                                req.i.ifi_flags &= ~IFF_PROMISC;
 
232
                        } else
 
233
                                return on_off("promisc");
 
234
                } else if (strcmp(*argv, "trailers") == 0) {
 
235
                        NEXT_ARG();
 
236
                        req.i.ifi_change |= IFF_NOTRAILERS;
 
237
                        if (strcmp(*argv, "off") == 0) {
 
238
                                req.i.ifi_flags |= IFF_NOTRAILERS;
 
239
                        } else if (strcmp(*argv, "on") == 0) {
 
240
                                req.i.ifi_flags &= ~IFF_NOTRAILERS;
 
241
                        } else
 
242
                                return on_off("trailers");
 
243
                } else if (strcmp(*argv, "arp") == 0) {
 
244
                        NEXT_ARG();
 
245
                        req.i.ifi_change |= IFF_NOARP;
 
246
                        if (strcmp(*argv, "on") == 0) {
 
247
                                req.i.ifi_flags &= ~IFF_NOARP;
 
248
                        } else if (strcmp(*argv, "off") == 0) {
 
249
                                req.i.ifi_flags |= IFF_NOARP;
 
250
                        } else
 
251
                                return on_off("noarp");
 
252
#ifdef IFF_DYNAMIC
 
253
                } else if (matches(*argv, "dynamic") == 0) {
 
254
                        NEXT_ARG();
 
255
                        req.i.ifi_change |= IFF_DYNAMIC;
 
256
                        if (strcmp(*argv, "on") == 0) {
 
257
                                req.i.ifi_flags |= IFF_DYNAMIC;
 
258
                        } else if (strcmp(*argv, "off") == 0) {
 
259
                                req.i.ifi_flags &= ~IFF_DYNAMIC;
 
260
                        } else
 
261
                                return on_off("dynamic");
 
262
#endif
 
263
                } else if (matches(*argv, "type") == 0) {
 
264
                        NEXT_ARG();
 
265
                        type = *argv;
 
266
                        argc--; argv++;
 
267
                        break;
 
268
                } else {
 
269
                        if (strcmp(*argv, "dev") == 0) {
 
270
                                NEXT_ARG();
 
271
                        }
 
272
                        if (dev)
 
273
                                duparg2("dev", *argv);
 
274
                        dev = *argv;
 
275
                }
 
276
                argc--; argv++;
 
277
        }
 
278
 
 
279
        ll_init_map(&rth);
 
280
 
 
281
        if (type) {
 
282
                struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
 
283
                addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
 
284
                addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
 
285
                         strlen(type));
 
286
 
 
287
                lu = get_link_kind(type);
 
288
                if (lu && argc) {
 
289
                        struct rtattr * data = NLMSG_TAIL(&req.n);
 
290
                        addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
 
291
 
 
292
                        if (lu->parse_opt &&
 
293
                            lu->parse_opt(lu, argc, argv, &req.n))
 
294
                                return -1;
 
295
 
 
296
                        data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
 
297
                } else if (argc) {
 
298
                        if (matches(*argv, "help") == 0)
 
299
                                usage();
 
300
                        fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
 
301
                                        "Try \"ip link help\".\n", *argv);
 
302
                        return -1;
 
303
                }
 
304
                linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
 
305
        }
 
306
 
 
307
        if (!(flags & NLM_F_CREATE)) {
 
308
                if (!dev) {
 
309
                        fprintf(stderr, "Not enough information: \"dev\" "
 
310
                                        "argument is required.\n");
 
311
                        exit(-1);
 
312
                }
 
313
 
 
314
                req.i.ifi_index = ll_name_to_index(dev);
 
315
                if (req.i.ifi_index == 0) {
 
316
                        fprintf(stderr, "Cannot find device \"%s\"\n", dev);
 
317
                        return -1;
 
318
                }
 
319
        } else {
 
320
                /* Allow "ip link add dev" and "ip link add name" */
 
321
                if (!name)
 
322
                        name = dev;
 
323
 
 
324
                if (link) {
 
325
                        int ifindex;
 
326
 
 
327
                        ifindex = ll_name_to_index(link);
 
328
                        if (ifindex == 0) {
 
329
                                fprintf(stderr, "Cannot find device \"%s\"\n",
 
330
                                        link);
 
331
                                return -1;
 
332
                        }
 
333
                        addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
 
334
                }
 
335
        }
 
336
 
 
337
        if (name) {
 
338
                len = strlen(name) + 1;
 
339
                if (len == 1)
 
340
                        invarg("\"\" is not a valid device identifier\n", "name");
 
341
                if (len > IFNAMSIZ)
 
342
                        invarg("\"name\" too long\n", name);
 
343
                addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
 
344
        }
 
345
 
 
346
        if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
 
347
                exit(2);
 
348
 
 
349
        return 0;
 
350
}
 
351
 
 
352
#if IPLINK_IOCTL_COMPAT
65
353
static int get_ctl_fd(void)
66
354
{
67
355
        int s_errno;
384
672
        }
385
673
 
386
674
        if (newname && strcmp(dev, newname)) {
 
675
                if (strlen(newname) == 0)
 
676
                        invarg("\"\" is not a valid device identifier\n", "name");
387
677
                if (do_changename(dev, newname) < 0)
388
678
                        return -1;
389
679
                dev = newname;
410
700
                return do_chflags(dev, flags, mask);
411
701
        return 0;
412
702
}
 
703
#endif /* IPLINK_IOCTL_COMPAT */
413
704
 
414
705
int do_iplink(int argc, char **argv)
415
706
{
416
707
        if (argc > 0) {
417
 
                if (matches(*argv, "set") == 0)
418
 
                        return do_set(argc-1, argv+1);
 
708
                if (iplink_have_newlink()) {
 
709
                        if (matches(*argv, "add") == 0)
 
710
                                return iplink_modify(RTM_NEWLINK,
 
711
                                                     NLM_F_CREATE|NLM_F_EXCL,
 
712
                                                     argc-1, argv+1);
 
713
                        if (matches(*argv, "set") == 0 ||
 
714
                            matches(*argv, "change") == 0)
 
715
                                return iplink_modify(RTM_NEWLINK, 0,
 
716
                                                     argc-1, argv+1);
 
717
                        if (matches(*argv, "replace") == 0)
 
718
                                return iplink_modify(RTM_NEWLINK,
 
719
                                                     NLM_F_CREATE|NLM_F_REPLACE,
 
720
                                                     argc-1, argv+1);
 
721
                        if (matches(*argv, "delete") == 0)
 
722
                                return iplink_modify(RTM_DELLINK, 0,
 
723
                                                     argc-1, argv+1);
 
724
                } else {
 
725
#if IPLINK_IOCTL_COMPAT
 
726
                        if (matches(*argv, "set") == 0)
 
727
                                return do_set(argc-1, argv+1);
 
728
#endif
 
729
                }
419
730
                if (matches(*argv, "show") == 0 ||
420
731
                    matches(*argv, "lst") == 0 ||
421
732
                    matches(*argv, "list") == 0)