blob: dc9801954ded1e64169a954ea0c8dde6795a622f [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
2 * iplink.c "ip link".
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: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <unistd.h>
16#include <syslog.h>
17#include <fcntl.h>
Patrick McHardy1d934832007-08-22 10:49:01 -070018#include <dlfcn.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000019#include <errno.h>
20#include <sys/socket.h>
21#include <linux/if.h>
22#include <linux/if_packet.h>
23#include <linux/if_ether.h>
24#include <linux/sockios.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <string.h>
28#include <sys/ioctl.h>
29#include <linux/sockios.h>
30
31#include "rt_names.h"
32#include "utils.h"
33#include "ip_common.h"
34
Patrick McHardy1d934832007-08-22 10:49:01 -070035#define IPLINK_IOCTL_COMPAT 1
Andreas Henriksson5e3bb532008-08-22 16:54:12 +020036#ifndef LIBDIR
Christoph J. Thompson5c434a92012-03-01 17:46:26 +010037#define LIBDIR "/usr/lib"
Rafael Almeidab514b352008-06-01 21:33:44 -030038#endif
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000039
40static void usage(void) __attribute__((noreturn));
Stephen Hemminger750a4052008-10-13 07:17:08 -070041static int iplink_have_newlink(void);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000042
43void iplink_usage(void)
44{
Stephen Hemminger750a4052008-10-13 07:17:08 -070045 if (iplink_have_newlink()) {
Sridhar Samudralaa22e9292011-10-06 16:10:51 -070046 fprintf(stderr, "Usage: ip link add [link DEV] [ name ] NAME\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070047 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
48 fprintf(stderr, " [ address LLADDR ]\n");
49 fprintf(stderr, " [ broadcast LLADDR ]\n");
50 fprintf(stderr, " [ mtu MTU ]\n");
Jiri Pirkod992f3e2012-08-01 16:19:55 -070051 fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n");
52 fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070053 fprintf(stderr, " type TYPE [ ARGS ]\n");
54 fprintf(stderr, " ip link delete DEV type TYPE [ ARGS ]\n");
55 fprintf(stderr, "\n");
Vlad Dogarudb026082011-02-02 20:23:41 +020056 fprintf(stderr, " ip link set { dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070057 } else
58 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
59
60 fprintf(stderr, " [ arp { on | off } ]\n");
61 fprintf(stderr, " [ dynamic { on | off } ]\n");
62 fprintf(stderr, " [ multicast { on | off } ]\n");
63 fprintf(stderr, " [ allmulticast { on | off } ]\n");
64 fprintf(stderr, " [ promisc { on | off } ]\n");
65 fprintf(stderr, " [ trailers { on | off } ]\n");
66 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
67 fprintf(stderr, " [ name NEWNAME ]\n");
68 fprintf(stderr, " [ address LLADDR ]\n");
69 fprintf(stderr, " [ broadcast LLADDR ]\n");
70 fprintf(stderr, " [ mtu MTU ]\n");
71 fprintf(stderr, " [ netns PID ]\n");
Eric W. Biederman0dc34c72011-07-13 09:48:26 -070072 fprintf(stderr, " [ netns NAME ]\n");
Stephen Hemmingerace9c962009-03-23 10:46:47 -070073 fprintf(stderr, " [ alias NAME ]\n");
Williams, Mitch Aae7229d2010-02-10 01:47:08 +000074 fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
75 fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
Greg Rose7b8179c2011-10-13 20:31:32 +000076
Stephen Hemminger1598b9e2011-01-13 14:53:02 -080077 fprintf(stderr, " [ rate TXRATE ] ] \n");
Greg Rose7b8179c2011-10-13 20:31:32 +000078
79 fprintf(stderr, " [ spoofchk { on | off} ] ] \n");
Jiri Pirkoa1e191b2011-02-25 19:55:19 -080080 fprintf(stderr, " [ master DEVICE ]\n");
81 fprintf(stderr, " [ nomaster ]\n");
Petr Ĺ abata44051232013-03-14 15:10:44 +010082 fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070083
84 if (iplink_have_newlink()) {
85 fprintf(stderr, "\n");
Nicolas Dichtel9d0efc12012-12-12 09:09:23 -080086 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can |\n");
Zhi Yong Wu602e9d32012-12-16 00:21:08 +080087 fprintf(stderr, " bridge | ipoib | ip6tnl | ipip | sit | vxlan }\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070088 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000089 exit(-1);
90}
91
92static void usage(void)
93{
94 iplink_usage();
95}
96
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +000097static int on_off(const char *msg, const char *realval)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000098{
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +000099 fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", msg, realval);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000100 return -1;
101}
102
Patrick McHardy1d934832007-08-22 10:49:01 -0700103static void *BODY; /* cached dlopen(NULL) handle */
104static struct link_util *linkutil_list;
105
106struct link_util *get_link_kind(const char *id)
107{
108 void *dlh;
109 char buf[256];
110 struct link_util *l;
111
112 for (l = linkutil_list; l; l = l->next)
113 if (strcmp(l->id, id) == 0)
114 return l;
115
Andreas Henriksson5e3bb532008-08-22 16:54:12 +0200116 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
Patrick McHardy1d934832007-08-22 10:49:01 -0700117 dlh = dlopen(buf, RTLD_LAZY);
118 if (dlh == NULL) {
119 /* look in current binary, only open once */
120 dlh = BODY;
121 if (dlh == NULL) {
122 dlh = BODY = dlopen(NULL, RTLD_LAZY);
123 if (dlh == NULL)
124 return NULL;
125 }
126 }
127
128 snprintf(buf, sizeof(buf), "%s_link_util", id);
129 l = dlsym(dlh, buf);
130 if (l == NULL)
131 return NULL;
132
133 l->next = linkutil_list;
134 linkutil_list = l;
135 return l;
136}
137
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800138static int get_link_mode(const char *mode)
Stephen Hemminger82499282012-03-19 17:24:43 -0700139{
Stephen Hemminger4ccfb442012-04-05 15:10:19 -0700140 if (strcasecmp(mode, "default") == 0)
Stephen Hemminger82499282012-03-19 17:24:43 -0700141 return IF_LINK_MODE_DEFAULT;
Stephen Hemminger4ccfb442012-04-05 15:10:19 -0700142 if (strcasecmp(mode, "dormant") == 0)
Stephen Hemminger82499282012-03-19 17:24:43 -0700143 return IF_LINK_MODE_DORMANT;
144 return -1;
145}
146
Patrick McHardy1d934832007-08-22 10:49:01 -0700147#if IPLINK_IOCTL_COMPAT
148static int have_rtnl_newlink = -1;
149
150static int accept_msg(const struct sockaddr_nl *who,
151 struct nlmsghdr *n, void *arg)
152{
153 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
154
Patrick McHardy66e529f2007-10-25 19:46:29 +0200155 if (n->nlmsg_type == NLMSG_ERROR &&
156 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
Patrick McHardy1d934832007-08-22 10:49:01 -0700157 have_rtnl_newlink = 0;
158 else
159 have_rtnl_newlink = 1;
160 return -1;
161}
162
163static int iplink_have_newlink(void)
164{
165 struct {
166 struct nlmsghdr n;
167 struct ifinfomsg i;
168 char buf[1024];
169 } req;
170
171 if (have_rtnl_newlink < 0) {
172 memset(&req, 0, sizeof(req));
173
174 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
175 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
176 req.n.nlmsg_type = RTM_NEWLINK;
177 req.i.ifi_family = AF_UNSPEC;
178
Stephen Hemminger6cf83982011-12-23 10:40:04 -0800179 rtnl_send(&rth, &req.n, req.n.nlmsg_len);
Patrick McHardy1d934832007-08-22 10:49:01 -0700180 rtnl_listen(&rth, accept_msg, NULL);
181 }
182 return have_rtnl_newlink;
183}
184#else /* IPLINK_IOCTL_COMPAT */
185static int iplink_have_newlink(void)
186{
187 return 1;
188}
189#endif /* ! IPLINK_IOCTL_COMPAT */
190
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400191struct iplink_req {
192 struct nlmsghdr n;
193 struct ifinfomsg i;
194 char buf[1024];
195};
196
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800197static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800198 struct iplink_req *req)
Roopa Prabhu632110a2010-11-09 14:47:52 +0000199{
200 int len, argc = *argcp;
201 char **argv = *argvp;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000202 struct rtattr *vfinfo;
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800203
204 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
Roopa Prabhu632110a2010-11-09 14:47:52 +0000205
206 while (NEXT_ARG_OK()) {
207 NEXT_ARG();
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800208 if (matches(*argv, "mac") == 0) {
209 struct ifla_vf_mac ivm;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000210 NEXT_ARG();
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800211 ivm.vf = vf;
212 len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
213 if (len < 0)
214 return -1;
215 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
Roopa Prabhu632110a2010-11-09 14:47:52 +0000216 } else if (matches(*argv, "vlan") == 0) {
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800217 struct ifla_vf_vlan ivv;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000218 NEXT_ARG();
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800219 if (get_unsigned(&ivv.vlan, *argv, 0)) {
220 invarg("Invalid \"vlan\" value\n", *argv);
221 }
222 ivv.vf = vf;
223 ivv.qos = 0;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000224 if (NEXT_ARG_OK()) {
225 NEXT_ARG();
226 if (matches(*argv, "qos") == 0) {
227 NEXT_ARG();
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800228 if (get_unsigned(&ivv.qos, *argv, 0)) {
229 invarg("Invalid \"qos\" value\n", *argv);
230 }
Roopa Prabhu632110a2010-11-09 14:47:52 +0000231 } else {
232 /* rewind arg */
233 PREV_ARG();
234 }
235 }
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800236 addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
Roopa Prabhu632110a2010-11-09 14:47:52 +0000237 } else if (matches(*argv, "rate") == 0) {
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800238 struct ifla_vf_tx_rate ivt;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000239 NEXT_ARG();
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800240 if (get_unsigned(&ivt.rate, *argv, 0)) {
241 invarg("Invalid \"rate\" value\n", *argv);
242 }
243 ivt.vf = vf;
244 addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
245
Greg Rose7b8179c2011-10-13 20:31:32 +0000246 } else if (matches(*argv, "spoofchk") == 0) {
247 struct ifla_vf_spoofchk ivs;
248 NEXT_ARG();
249 if (matches(*argv, "on") == 0)
250 ivs.setting = 1;
251 else if (matches(*argv, "off") == 0)
252 ivs.setting = 0;
253 else
254 invarg("Invalid \"spoofchk\" value\n", *argv);
255 ivs.vf = vf;
256 addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
257
Roopa Prabhu632110a2010-11-09 14:47:52 +0000258 } else {
259 /* rewind arg */
260 PREV_ARG();
261 break;
262 }
263 }
264
265 if (argc == *argcp)
266 incomplete_command();
267
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800268 addattr_nest_end(&req->n, vfinfo);
Roopa Prabhu632110a2010-11-09 14:47:52 +0000269
270 *argcp = argc;
271 *argvp = argv;
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800272 return 0;
Chris Wright3fd86632010-05-18 00:57:00 -0700273}
274
275
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400276int iplink_parse(int argc, char **argv, struct iplink_req *req,
Vlad Dogarudb026082011-02-02 20:23:41 +0200277 char **name, char **type, char **link, char **dev, int *group)
Patrick McHardy1d934832007-08-22 10:49:01 -0700278{
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400279 int ret, len;
280 char abuf[32];
Patrick McHardy1d934832007-08-22 10:49:01 -0700281 int qlen = -1;
282 int mtu = -1;
Benjamin Therye2613dc2008-06-20 11:07:35 +0200283 int netns = -1;
Williams, Mitch Aae7229d2010-02-10 01:47:08 +0000284 int vf = -1;
Jiri Pirkod992f3e2012-08-01 16:19:55 -0700285 int numtxqueues = -1;
286 int numrxqueues = -1;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400287
Vlad Dogarudb026082011-02-02 20:23:41 +0200288 *group = -1;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400289 ret = argc;
290
291 while (argc > 0) {
292 if (strcmp(*argv, "up") == 0) {
293 req->i.ifi_change |= IFF_UP;
294 req->i.ifi_flags |= IFF_UP;
295 } else if (strcmp(*argv, "down") == 0) {
296 req->i.ifi_change |= IFF_UP;
297 req->i.ifi_flags &= ~IFF_UP;
298 } else if (strcmp(*argv, "name") == 0) {
299 NEXT_ARG();
300 *name = *argv;
301 } else if (matches(*argv, "link") == 0) {
302 NEXT_ARG();
303 *link = *argv;
304 } else if (matches(*argv, "address") == 0) {
305 NEXT_ARG();
306 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
Andreas Henrikssoncb2eb992009-04-30 16:50:50 +0200307 if (len < 0)
308 return -1;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400309 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
310 } else if (matches(*argv, "broadcast") == 0 ||
311 strcmp(*argv, "brd") == 0) {
312 NEXT_ARG();
313 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
Andreas Henrikssoncb2eb992009-04-30 16:50:50 +0200314 if (len < 0)
315 return -1;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400316 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
317 } else if (matches(*argv, "txqueuelen") == 0 ||
318 strcmp(*argv, "qlen") == 0 ||
319 matches(*argv, "txqlen") == 0) {
320 NEXT_ARG();
321 if (qlen != -1)
322 duparg("txqueuelen", *argv);
323 if (get_integer(&qlen, *argv, 0))
324 invarg("Invalid \"txqueuelen\" value\n", *argv);
325 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
326 } else if (strcmp(*argv, "mtu") == 0) {
327 NEXT_ARG();
328 if (mtu != -1)
329 duparg("mtu", *argv);
330 if (get_integer(&mtu, *argv, 0))
331 invarg("Invalid \"mtu\" value\n", *argv);
332 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
Benjamin Therye2613dc2008-06-20 11:07:35 +0200333 } else if (strcmp(*argv, "netns") == 0) {
334 NEXT_ARG();
335 if (netns != -1)
336 duparg("netns", *argv);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700337 if ((netns = get_netns_fd(*argv)) >= 0)
338 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
339 else if (get_integer(&netns, *argv, 0) == 0)
340 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
341 else
Benjamin Therye2613dc2008-06-20 11:07:35 +0200342 invarg("Invalid \"netns\" value\n", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400343 } else if (strcmp(*argv, "multicast") == 0) {
344 NEXT_ARG();
345 req->i.ifi_change |= IFF_MULTICAST;
346 if (strcmp(*argv, "on") == 0) {
347 req->i.ifi_flags |= IFF_MULTICAST;
348 } else if (strcmp(*argv, "off") == 0) {
349 req->i.ifi_flags &= ~IFF_MULTICAST;
350 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000351 return on_off("multicast", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400352 } else if (strcmp(*argv, "allmulticast") == 0) {
353 NEXT_ARG();
354 req->i.ifi_change |= IFF_ALLMULTI;
355 if (strcmp(*argv, "on") == 0) {
356 req->i.ifi_flags |= IFF_ALLMULTI;
357 } else if (strcmp(*argv, "off") == 0) {
358 req->i.ifi_flags &= ~IFF_ALLMULTI;
359 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000360 return on_off("allmulticast", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400361 } else if (strcmp(*argv, "promisc") == 0) {
362 NEXT_ARG();
363 req->i.ifi_change |= IFF_PROMISC;
364 if (strcmp(*argv, "on") == 0) {
365 req->i.ifi_flags |= IFF_PROMISC;
366 } else if (strcmp(*argv, "off") == 0) {
367 req->i.ifi_flags &= ~IFF_PROMISC;
368 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000369 return on_off("promisc", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400370 } else if (strcmp(*argv, "trailers") == 0) {
371 NEXT_ARG();
372 req->i.ifi_change |= IFF_NOTRAILERS;
373 if (strcmp(*argv, "off") == 0) {
374 req->i.ifi_flags |= IFF_NOTRAILERS;
375 } else if (strcmp(*argv, "on") == 0) {
376 req->i.ifi_flags &= ~IFF_NOTRAILERS;
377 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000378 return on_off("trailers", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400379 } else if (strcmp(*argv, "arp") == 0) {
380 NEXT_ARG();
381 req->i.ifi_change |= IFF_NOARP;
382 if (strcmp(*argv, "on") == 0) {
383 req->i.ifi_flags &= ~IFF_NOARP;
384 } else if (strcmp(*argv, "off") == 0) {
385 req->i.ifi_flags |= IFF_NOARP;
386 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000387 return on_off("noarp", *argv);
Williams, Mitch Aae7229d2010-02-10 01:47:08 +0000388 } else if (strcmp(*argv, "vf") == 0) {
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800389 struct rtattr *vflist;
Williams, Mitch Aae7229d2010-02-10 01:47:08 +0000390 NEXT_ARG();
391 if (get_integer(&vf, *argv, 0)) {
392 invarg("Invalid \"vf\" value\n", *argv);
393 }
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800394 vflist = addattr_nest(&req->n, sizeof(*req),
395 IFLA_VFINFO_LIST);
396 len = iplink_parse_vf(vf, &argc, &argv, req);
397 if (len < 0)
398 return -1;
399 addattr_nest_end(&req->n, vflist);
Jiri Pirkoa1e191b2011-02-25 19:55:19 -0800400 } else if (matches(*argv, "master") == 0) {
401 int ifindex;
402 NEXT_ARG();
403 ifindex = ll_name_to_index(*argv);
404 if (!ifindex)
405 invarg("Device does not exist\n", *argv);
406 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
407 &ifindex, 4);
408 } else if (matches(*argv, "nomaster") == 0) {
409 int ifindex = 0;
410 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
411 &ifindex, 4);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400412 } else if (matches(*argv, "dynamic") == 0) {
413 NEXT_ARG();
414 req->i.ifi_change |= IFF_DYNAMIC;
415 if (strcmp(*argv, "on") == 0) {
416 req->i.ifi_flags |= IFF_DYNAMIC;
417 } else if (strcmp(*argv, "off") == 0) {
418 req->i.ifi_flags &= ~IFF_DYNAMIC;
419 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000420 return on_off("dynamic", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400421 } else if (matches(*argv, "type") == 0) {
422 NEXT_ARG();
423 *type = *argv;
424 argc--; argv++;
425 break;
Stephen Hemmingerace9c962009-03-23 10:46:47 -0700426 } else if (matches(*argv, "alias") == 0) {
427 NEXT_ARG();
428 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
429 *argv, strlen(*argv));
430 argc--; argv++;
431 break;
Vlad Dogarudb026082011-02-02 20:23:41 +0200432 } else if (strcmp(*argv, "group") == 0) {
433 NEXT_ARG();
434 if (*group != -1)
435 duparg("group", *argv);
436 if (rtnl_group_a2n(group, *argv))
437 invarg("Invalid \"group\" value\n", *argv);
Stephen Hemminger82499282012-03-19 17:24:43 -0700438 } else if (strcmp(*argv, "mode") == 0) {
439 int mode;
440 NEXT_ARG();
Stephen Hemminger4ccfb442012-04-05 15:10:19 -0700441 mode = get_link_mode(*argv);
Stephen Hemminger82499282012-03-19 17:24:43 -0700442 if (mode < 0)
443 invarg("Invalid link mode\n", *argv);
444 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
Stephen Hemminger4f2fdd42012-04-05 15:08:57 -0700445 } else if (strcmp(*argv, "state") == 0) {
446 int state;
447 NEXT_ARG();
448 state = get_operstate(*argv);
449 if (state < 0)
450 invarg("Invalid operstate\n", *argv);
451
452 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
Jiri Pirkod992f3e2012-08-01 16:19:55 -0700453 } else if (matches(*argv, "numtxqueues") == 0) {
454 NEXT_ARG();
455 if (numtxqueues != -1)
456 duparg("numtxqueues", *argv);
457 if (get_integer(&numtxqueues, *argv, 0))
458 invarg("Invalid \"numtxqueues\" value\n", *argv);
459 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
460 &numtxqueues, 4);
461 } else if (matches(*argv, "numrxqueues") == 0) {
462 NEXT_ARG();
463 if (numrxqueues != -1)
464 duparg("numrxqueues", *argv);
465 if (get_integer(&numrxqueues, *argv, 0))
466 invarg("Invalid \"numrxqueues\" value\n", *argv);
467 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
468 &numrxqueues, 4);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400469 } else {
470 if (strcmp(*argv, "dev") == 0) {
471 NEXT_ARG();
472 }
Patrick McHardy05325552008-10-07 17:16:08 +0200473 if (matches(*argv, "help") == 0)
474 usage();
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400475 if (*dev)
476 duparg2("dev", *argv);
477 *dev = *argv;
478 }
479 argc--; argv++;
480 }
481
482 return ret - argc;
483}
484
485static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
486{
Patrick McHardy1d934832007-08-22 10:49:01 -0700487 int len;
Patrick McHardy1d934832007-08-22 10:49:01 -0700488 char *dev = NULL;
489 char *name = NULL;
490 char *link = NULL;
491 char *type = NULL;
Vlad Dogarudb026082011-02-02 20:23:41 +0200492 int group;
Patrick McHardy1d934832007-08-22 10:49:01 -0700493 struct link_util *lu = NULL;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400494 struct iplink_req req;
495 int ret;
Patrick McHardy1d934832007-08-22 10:49:01 -0700496
497 memset(&req, 0, sizeof(req));
498
499 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
500 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
501 req.n.nlmsg_type = cmd;
502 req.i.ifi_family = preferred_family;
503
Vlad Dogarudb026082011-02-02 20:23:41 +0200504 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400505 if (ret < 0)
506 return ret;
Patrick McHardy1d934832007-08-22 10:49:01 -0700507
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400508 argc -= ret;
509 argv += ret;
Vlad Dogarudb026082011-02-02 20:23:41 +0200510
511 if (group != -1) {
512 if (dev)
513 addattr_l(&req.n, sizeof(req), IFLA_GROUP,
514 &group, sizeof(group));
515 else {
516 if (argc) {
517 fprintf(stderr, "Garbage instead of arguments "
518 "\"%s ...\". Try \"ip link "
519 "help\".\n", *argv);
520 return -1;
521 }
522 if (flags & NLM_F_CREATE) {
523 fprintf(stderr, "group cannot be used when "
524 "creating devices.\n");
525 return -1;
526 }
527
528 req.i.ifi_index = 0;
529 addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
Stephen Hemmingercd70f3f2011-12-28 10:37:12 -0800530 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
Vlad Dogarudb026082011-02-02 20:23:41 +0200531 exit(2);
532 return 0;
533 }
534 }
535
Patrick McHardy1d934832007-08-22 10:49:01 -0700536 if (!(flags & NLM_F_CREATE)) {
537 if (!dev) {
538 fprintf(stderr, "Not enough information: \"dev\" "
539 "argument is required.\n");
540 exit(-1);
541 }
542
543 req.i.ifi_index = ll_name_to_index(dev);
544 if (req.i.ifi_index == 0) {
545 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
546 return -1;
547 }
548 } else {
549 /* Allow "ip link add dev" and "ip link add name" */
550 if (!name)
551 name = dev;
552
553 if (link) {
554 int ifindex;
555
556 ifindex = ll_name_to_index(link);
557 if (ifindex == 0) {
558 fprintf(stderr, "Cannot find device \"%s\"\n",
559 link);
560 return -1;
561 }
562 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
563 }
564 }
565
566 if (name) {
567 len = strlen(name) + 1;
Patrick McHardyca78b0e2007-10-12 14:01:13 +0200568 if (len == 1)
569 invarg("\"\" is not a valid device identifier\n", "name");
Patrick McHardy1d934832007-08-22 10:49:01 -0700570 if (len > IFNAMSIZ)
Patrick McHardyca78b0e2007-10-12 14:01:13 +0200571 invarg("\"name\" too long\n", name);
Patrick McHardy1d934832007-08-22 10:49:01 -0700572 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
573 }
574
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700575 if (type) {
576 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
577 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
578 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
579 strlen(type));
580
581 lu = get_link_kind(type);
582 if (lu && argc) {
583 struct rtattr * data = NLMSG_TAIL(&req.n);
584 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
585
586 if (lu->parse_opt &&
587 lu->parse_opt(lu, argc, argv, &req.n))
588 return -1;
589
590 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
591 } else if (argc) {
592 if (matches(*argv, "help") == 0)
593 usage();
594 fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
595 "Try \"ip link help\".\n", *argv);
596 return -1;
597 }
598 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
599 } else if (flags & NLM_F_CREATE) {
600 fprintf(stderr, "Not enough information: \"type\" argument "
601 "is required\n");
602 return -1;
603 }
604
Stephen Hemmingercd70f3f2011-12-28 10:37:12 -0800605 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
Patrick McHardy1d934832007-08-22 10:49:01 -0700606 exit(2);
607
608 return 0;
609}
610
611#if IPLINK_IOCTL_COMPAT
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000612static int get_ctl_fd(void)
613{
614 int s_errno;
615 int fd;
616
617 fd = socket(PF_INET, SOCK_DGRAM, 0);
618 if (fd >= 0)
619 return fd;
620 s_errno = errno;
621 fd = socket(PF_PACKET, SOCK_DGRAM, 0);
622 if (fd >= 0)
623 return fd;
624 fd = socket(PF_INET6, SOCK_DGRAM, 0);
625 if (fd >= 0)
626 return fd;
627 errno = s_errno;
628 perror("Cannot create control socket");
629 return -1;
630}
631
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000632static int do_chflags(const char *dev, __u32 flags, __u32 mask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000633{
634 struct ifreq ifr;
635 int fd;
636 int err;
637
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000638 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000639 fd = get_ctl_fd();
640 if (fd < 0)
641 return -1;
642 err = ioctl(fd, SIOCGIFFLAGS, &ifr);
643 if (err) {
644 perror("SIOCGIFFLAGS");
645 close(fd);
646 return -1;
647 }
648 if ((ifr.ifr_flags^flags)&mask) {
649 ifr.ifr_flags &= ~mask;
650 ifr.ifr_flags |= mask&flags;
651 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
652 if (err)
653 perror("SIOCSIFFLAGS");
654 }
655 close(fd);
656 return err;
657}
658
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000659static int do_changename(const char *dev, const char *newdev)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000660{
661 struct ifreq ifr;
662 int fd;
663 int err;
664
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000665 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
666 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000667 fd = get_ctl_fd();
668 if (fd < 0)
669 return -1;
670 err = ioctl(fd, SIOCSIFNAME, &ifr);
671 if (err) {
672 perror("SIOCSIFNAME");
673 close(fd);
674 return -1;
675 }
676 close(fd);
677 return err;
678}
679
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000680static int set_qlen(const char *dev, int qlen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000681{
682 struct ifreq ifr;
683 int s;
684
685 s = get_ctl_fd();
686 if (s < 0)
687 return -1;
688
689 memset(&ifr, 0, sizeof(ifr));
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800690 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
691 ifr.ifr_qlen = qlen;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000692 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
693 perror("SIOCSIFXQLEN");
694 close(s);
695 return -1;
696 }
697 close(s);
698
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800699 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000700}
701
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000702static int set_mtu(const char *dev, int mtu)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000703{
704 struct ifreq ifr;
705 int s;
706
707 s = get_ctl_fd();
708 if (s < 0)
709 return -1;
710
711 memset(&ifr, 0, sizeof(ifr));
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800712 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
713 ifr.ifr_mtu = mtu;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000714 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
715 perror("SIOCSIFMTU");
716 close(s);
717 return -1;
718 }
719 close(s);
720
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800721 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000722}
723
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000724static int get_address(const char *dev, int *htype)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000725{
726 struct ifreq ifr;
727 struct sockaddr_ll me;
shemmingerf332d162005-07-05 22:37:15 +0000728 socklen_t alen;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000729 int s;
730
731 s = socket(PF_PACKET, SOCK_DGRAM, 0);
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800732 if (s < 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000733 perror("socket(PF_PACKET)");
734 return -1;
735 }
736
737 memset(&ifr, 0, sizeof(ifr));
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000738 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000739 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
740 perror("SIOCGIFINDEX");
741 close(s);
742 return -1;
743 }
744
745 memset(&me, 0, sizeof(me));
746 me.sll_family = AF_PACKET;
747 me.sll_ifindex = ifr.ifr_ifindex;
748 me.sll_protocol = htons(ETH_P_LOOP);
749 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
750 perror("bind");
751 close(s);
752 return -1;
753 }
754
755 alen = sizeof(me);
756 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
757 perror("getsockname");
758 close(s);
759 return -1;
760 }
761 close(s);
762 *htype = me.sll_hatype;
763 return me.sll_halen;
764}
765
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800766static int parse_address(const char *dev, int hatype, int halen,
shemminger7b565752006-03-21 23:57:50 +0000767 char *lla, struct ifreq *ifr)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000768{
769 int alen;
770
771 memset(ifr, 0, sizeof(*ifr));
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000772 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000773 ifr->ifr_hwaddr.sa_family = hatype;
774 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
775 if (alen < 0)
776 return -1;
777 if (alen != halen) {
778 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
779 return -1;
780 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800781 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000782}
783
784static int set_address(struct ifreq *ifr, int brd)
785{
786 int s;
787
788 s = get_ctl_fd();
789 if (s < 0)
790 return -1;
791 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
792 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
793 close(s);
794 return -1;
795 }
796 close(s);
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800797 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000798}
799
800
801static int do_set(int argc, char **argv)
802{
803 char *dev = NULL;
804 __u32 mask = 0;
805 __u32 flags = 0;
806 int qlen = -1;
807 int mtu = -1;
808 char *newaddr = NULL;
809 char *newbrd = NULL;
810 struct ifreq ifr0, ifr1;
811 char *newname = NULL;
812 int htype, halen;
813
814 while (argc > 0) {
815 if (strcmp(*argv, "up") == 0) {
816 mask |= IFF_UP;
817 flags |= IFF_UP;
818 } else if (strcmp(*argv, "down") == 0) {
819 mask |= IFF_UP;
820 flags &= ~IFF_UP;
821 } else if (strcmp(*argv, "name") == 0) {
822 NEXT_ARG();
823 newname = *argv;
824 } else if (matches(*argv, "address") == 0) {
825 NEXT_ARG();
826 newaddr = *argv;
827 } else if (matches(*argv, "broadcast") == 0 ||
828 strcmp(*argv, "brd") == 0) {
829 NEXT_ARG();
830 newbrd = *argv;
831 } else if (matches(*argv, "txqueuelen") == 0 ||
832 strcmp(*argv, "qlen") == 0 ||
833 matches(*argv, "txqlen") == 0) {
834 NEXT_ARG();
835 if (qlen != -1)
836 duparg("txqueuelen", *argv);
837 if (get_integer(&qlen, *argv, 0))
838 invarg("Invalid \"txqueuelen\" value\n", *argv);
839 } else if (strcmp(*argv, "mtu") == 0) {
840 NEXT_ARG();
841 if (mtu != -1)
842 duparg("mtu", *argv);
843 if (get_integer(&mtu, *argv, 0))
844 invarg("Invalid \"mtu\" value\n", *argv);
845 } else if (strcmp(*argv, "multicast") == 0) {
846 NEXT_ARG();
847 mask |= IFF_MULTICAST;
848 if (strcmp(*argv, "on") == 0) {
849 flags |= IFF_MULTICAST;
850 } else if (strcmp(*argv, "off") == 0) {
851 flags &= ~IFF_MULTICAST;
852 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000853 return on_off("multicast", *argv);
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +0000854 } else if (strcmp(*argv, "allmulticast") == 0) {
855 NEXT_ARG();
856 mask |= IFF_ALLMULTI;
857 if (strcmp(*argv, "on") == 0) {
858 flags |= IFF_ALLMULTI;
859 } else if (strcmp(*argv, "off") == 0) {
860 flags &= ~IFF_ALLMULTI;
861 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000862 return on_off("allmulticast", *argv);
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +0000863 } else if (strcmp(*argv, "promisc") == 0) {
864 NEXT_ARG();
865 mask |= IFF_PROMISC;
866 if (strcmp(*argv, "on") == 0) {
867 flags |= IFF_PROMISC;
868 } else if (strcmp(*argv, "off") == 0) {
869 flags &= ~IFF_PROMISC;
870 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000871 return on_off("promisc", *argv);
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +0000872 } else if (strcmp(*argv, "trailers") == 0) {
873 NEXT_ARG();
874 mask |= IFF_NOTRAILERS;
875 if (strcmp(*argv, "off") == 0) {
876 flags |= IFF_NOTRAILERS;
877 } else if (strcmp(*argv, "on") == 0) {
878 flags &= ~IFF_NOTRAILERS;
879 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000880 return on_off("trailers", *argv);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000881 } else if (strcmp(*argv, "arp") == 0) {
882 NEXT_ARG();
883 mask |= IFF_NOARP;
884 if (strcmp(*argv, "on") == 0) {
885 flags &= ~IFF_NOARP;
886 } else if (strcmp(*argv, "off") == 0) {
887 flags |= IFF_NOARP;
888 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000889 return on_off("noarp", *argv);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000890 } else if (matches(*argv, "dynamic") == 0) {
891 NEXT_ARG();
892 mask |= IFF_DYNAMIC;
893 if (strcmp(*argv, "on") == 0) {
894 flags |= IFF_DYNAMIC;
895 } else if (strcmp(*argv, "off") == 0) {
896 flags &= ~IFF_DYNAMIC;
897 } else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000898 return on_off("dynamic", *argv);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000899 } else {
900 if (strcmp(*argv, "dev") == 0) {
901 NEXT_ARG();
902 }
903 if (matches(*argv, "help") == 0)
904 usage();
905 if (dev)
906 duparg2("dev", *argv);
907 dev = *argv;
908 }
909 argc--; argv++;
910 }
911
912 if (!dev) {
913 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
914 exit(-1);
915 }
916
917 if (newaddr || newbrd) {
918 halen = get_address(dev, &htype);
919 if (halen < 0)
920 return -1;
921 if (newaddr) {
922 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
923 return -1;
924 }
925 if (newbrd) {
926 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800927 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000928 }
929 }
930
931 if (newname && strcmp(dev, newname)) {
Patrick McHardyca78b0e2007-10-12 14:01:13 +0200932 if (strlen(newname) == 0)
933 invarg("\"\" is not a valid device identifier\n", "name");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000934 if (do_changename(dev, newname) < 0)
935 return -1;
936 dev = newname;
937 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800938 if (qlen != -1) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000939 if (set_qlen(dev, qlen) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800940 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000941 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800942 if (mtu != -1) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000943 if (set_mtu(dev, mtu) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800944 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000945 }
946 if (newaddr || newbrd) {
947 if (newbrd) {
948 if (set_address(&ifr1, 1) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800949 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000950 }
951 if (newaddr) {
952 if (set_address(&ifr0, 0) < 0)
953 return -1;
954 }
955 }
956 if (mask)
957 return do_chflags(dev, flags, mask);
958 return 0;
959}
Patrick McHardy1d934832007-08-22 10:49:01 -0700960#endif /* IPLINK_IOCTL_COMPAT */
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000961
962int do_iplink(int argc, char **argv)
963{
964 if (argc > 0) {
Patrick McHardy1d934832007-08-22 10:49:01 -0700965 if (iplink_have_newlink()) {
966 if (matches(*argv, "add") == 0)
967 return iplink_modify(RTM_NEWLINK,
968 NLM_F_CREATE|NLM_F_EXCL,
969 argc-1, argv+1);
970 if (matches(*argv, "set") == 0 ||
971 matches(*argv, "change") == 0)
972 return iplink_modify(RTM_NEWLINK, 0,
973 argc-1, argv+1);
974 if (matches(*argv, "replace") == 0)
975 return iplink_modify(RTM_NEWLINK,
976 NLM_F_CREATE|NLM_F_REPLACE,
977 argc-1, argv+1);
978 if (matches(*argv, "delete") == 0)
979 return iplink_modify(RTM_DELLINK, 0,
980 argc-1, argv+1);
981 } else {
982#if IPLINK_IOCTL_COMPAT
983 if (matches(*argv, "set") == 0)
984 return do_set(argc-1, argv+1);
985#endif
986 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000987 if (matches(*argv, "show") == 0 ||
988 matches(*argv, "lst") == 0 ||
989 matches(*argv, "list") == 0)
990 return ipaddr_list_link(argc-1, argv+1);
991 if (matches(*argv, "help") == 0)
992 usage();
993 } else
994 return ipaddr_list_link(0, NULL);
995
996 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
997 exit(-1);
998}