]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink.c
libnetlink: add size argument to rtnl_talk
[mirror_iproute2.git] / ip / iplink.c
CommitLineData
aba5acdf
SH
1/*
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>
1d934839 18#include <dlfcn.h>
aba5acdf
SH
19#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>
fbea6115 30#include <stdbool.h>
aba5acdf
SH
31
32#include "rt_names.h"
33#include "utils.h"
34#include "ip_common.h"
c3087c10 35#include "namespace.h"
aba5acdf 36
1d934839 37#define IPLINK_IOCTL_COMPAT 1
5e3bb534 38#ifndef LIBDIR
5c434a9e 39#define LIBDIR "/usr/lib"
b514b358 40#endif
aba5acdf
SH
41
42static void usage(void) __attribute__((noreturn));
750a405a 43static int iplink_have_newlink(void);
aba5acdf
SH
44
45void iplink_usage(void)
46{
750a405a 47 if (iplink_have_newlink()) {
a22e9295 48 fprintf(stderr, "Usage: ip link add [link DEV] [ name ] NAME\n");
750a405a
SH
49 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
50 fprintf(stderr, " [ address LLADDR ]\n");
51 fprintf(stderr, " [ broadcast LLADDR ]\n");
5e25cf77 52 fprintf(stderr, " [ mtu MTU ] [index IDX ]\n");
d992f3e6
JP
53 fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n");
54 fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n");
750a405a 55 fprintf(stderr, " type TYPE [ ARGS ]\n");
8916ccf6 56 fprintf(stderr, " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n");
750a405a 57 fprintf(stderr, "\n");
8916ccf6 58 fprintf(stderr, " ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
750a405a
SH
59 } else
60 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
61
62 fprintf(stderr, " [ arp { on | off } ]\n");
63 fprintf(stderr, " [ dynamic { on | off } ]\n");
64 fprintf(stderr, " [ multicast { on | off } ]\n");
65 fprintf(stderr, " [ allmulticast { on | off } ]\n");
66 fprintf(stderr, " [ promisc { on | off } ]\n");
67 fprintf(stderr, " [ trailers { on | off } ]\n");
68 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
69 fprintf(stderr, " [ name NEWNAME ]\n");
70 fprintf(stderr, " [ address LLADDR ]\n");
71 fprintf(stderr, " [ broadcast LLADDR ]\n");
72 fprintf(stderr, " [ mtu MTU ]\n");
73 fprintf(stderr, " [ netns PID ]\n");
0dc34c77 74 fprintf(stderr, " [ netns NAME ]\n");
21107f52 75 fprintf(stderr, " [ link-netnsid ID ]\n");
ace9c961 76 fprintf(stderr, " [ alias NAME ]\n");
ae7229d5
WM
77 fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
78 fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
7b8179c7 79
1598b9ef 80 fprintf(stderr, " [ rate TXRATE ] ] \n");
7b8179c7
GR
81
82 fprintf(stderr, " [ spoofchk { on | off} ] ] \n");
6c55c8c4 83 fprintf(stderr, " [ query_rss { on | off} ] ] \n");
07fa9c15 84 fprintf(stderr, " [ state { auto | enable | disable} ] ]\n");
a1e191b9
JP
85 fprintf(stderr, " [ master DEVICE ]\n");
86 fprintf(stderr, " [ nomaster ]\n");
ff7c2084 87 fprintf(stderr, " [ addrgenmode { eui64 | none } ]\n");
712249d8 88 fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]\n");
750a405a
SH
89
90 if (iplink_have_newlink()) {
561e650e 91 fprintf(stderr, " ip link help [ TYPE ]\n");
750a405a 92 fprintf(stderr, "\n");
1253a10a 93 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n");
2b70fe15 94 fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n");
620ddeda 95 fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n");
81eaf677 96 fprintf(stderr, " bond_slave | ipvlan }\n");
750a405a 97 }
aba5acdf
SH
98 exit(-1);
99}
100
101static void usage(void)
102{
103 iplink_usage();
104}
105
14645ec2 106static int on_off(const char *msg, const char *realval)
aba5acdf 107{
14645ec2 108 fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", msg, realval);
aba5acdf
SH
109 return -1;
110}
111
1d934839
PM
112static void *BODY; /* cached dlopen(NULL) handle */
113static struct link_util *linkutil_list;
114
fbea6115 115static struct link_util *__get_link_kind(const char *id, bool slave)
1d934839
PM
116{
117 void *dlh;
118 char buf[256];
119 struct link_util *l;
120
121 for (l = linkutil_list; l; l = l->next)
fbea6115
JP
122 if (strcmp(l->id, id) == 0 &&
123 l->slave == slave)
1d934839
PM
124 return l;
125
5e3bb534 126 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
1d934839
PM
127 dlh = dlopen(buf, RTLD_LAZY);
128 if (dlh == NULL) {
129 /* look in current binary, only open once */
130 dlh = BODY;
131 if (dlh == NULL) {
132 dlh = BODY = dlopen(NULL, RTLD_LAZY);
133 if (dlh == NULL)
134 return NULL;
135 }
136 }
137
fbea6115
JP
138 if (slave)
139 snprintf(buf, sizeof(buf), "%s_slave_link_util", id);
140 else
141 snprintf(buf, sizeof(buf), "%s_link_util", id);
1d934839
PM
142 l = dlsym(dlh, buf);
143 if (l == NULL)
144 return NULL;
145
146 l->next = linkutil_list;
147 linkutil_list = l;
148 return l;
149}
150
fbea6115
JP
151struct link_util *get_link_kind(const char *id)
152{
153 return __get_link_kind(id, false);
154}
155
156struct link_util *get_link_slave_kind(const char *id)
157{
158 return __get_link_kind(id, true);
159}
160
d1f28cf1 161static int get_link_mode(const char *mode)
82499282 162{
4ccfb44d 163 if (strcasecmp(mode, "default") == 0)
82499282 164 return IF_LINK_MODE_DEFAULT;
4ccfb44d 165 if (strcasecmp(mode, "dormant") == 0)
82499282
SH
166 return IF_LINK_MODE_DORMANT;
167 return -1;
168}
169
ff7c2084
JP
170static int get_addr_gen_mode(const char *mode)
171{
172 if (strcasecmp(mode, "eui64") == 0)
173 return IN6_ADDR_GEN_MODE_EUI64;
174 if (strcasecmp(mode, "none") == 0)
175 return IN6_ADDR_GEN_MODE_NONE;
176 return -1;
177}
178
1d934839
PM
179#if IPLINK_IOCTL_COMPAT
180static int have_rtnl_newlink = -1;
181
182static int accept_msg(const struct sockaddr_nl *who,
183 struct nlmsghdr *n, void *arg)
184{
185 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
186
66e529f5
PM
187 if (n->nlmsg_type == NLMSG_ERROR &&
188 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
1d934839
PM
189 have_rtnl_newlink = 0;
190 else
191 have_rtnl_newlink = 1;
192 return -1;
193}
194
195static int iplink_have_newlink(void)
196{
197 struct {
198 struct nlmsghdr n;
199 struct ifinfomsg i;
200 char buf[1024];
201 } req;
202
203 if (have_rtnl_newlink < 0) {
204 memset(&req, 0, sizeof(req));
205
206 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
207 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
208 req.n.nlmsg_type = RTM_NEWLINK;
209 req.i.ifi_family = AF_UNSPEC;
210
d2468da0
SH
211 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
212 perror("request send failed");
213 exit(1);
214 }
1d934839
PM
215 rtnl_listen(&rth, accept_msg, NULL);
216 }
217 return have_rtnl_newlink;
218}
219#else /* IPLINK_IOCTL_COMPAT */
220static int iplink_have_newlink(void)
221{
222 return 1;
223}
224#endif /* ! IPLINK_IOCTL_COMPAT */
225
909dfe2c
PE
226struct iplink_req {
227 struct nlmsghdr n;
228 struct ifinfomsg i;
229 char buf[1024];
230};
231
d1f28cf1 232static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
f89a2a05 233 struct iplink_req *req, int dev_index)
3fd86630 234{
f89a2a05
SC
235 char new_rate_api = 0, count = 0, override_legacy_rate = 0;
236 struct ifla_vf_rate tivt;
3fd86630
CW
237 int len, argc = *argcp;
238 char **argv = *argvp;
239 struct rtattr *vfinfo;
1598b9ef 240
f89a2a05
SC
241 tivt.min_tx_rate = -1;
242 tivt.max_tx_rate = -1;
243
1598b9ef 244 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
3fd86630 245
f89a2a05
SC
246 while (NEXT_ARG_OK()) {
247 NEXT_ARG();
248 count++;
249 if (!matches(*argv, "max_tx_rate")) {
250 /* new API in use */
251 new_rate_api = 1;
252 /* override legacy rate */
253 override_legacy_rate = 1;
254 } else if (!matches(*argv, "min_tx_rate")) {
255 /* new API in use */
256 new_rate_api = 1;
257 }
258 }
259
260 while (count--) {
261 /* rewind arg */
262 PREV_ARG();
263 }
264
3fd86630
CW
265 while (NEXT_ARG_OK()) {
266 NEXT_ARG();
1598b9ef
SH
267 if (matches(*argv, "mac") == 0) {
268 struct ifla_vf_mac ivm;
3fd86630 269 NEXT_ARG();
1598b9ef
SH
270 ivm.vf = vf;
271 len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
272 if (len < 0)
273 return -1;
274 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
3fd86630 275 } else if (matches(*argv, "vlan") == 0) {
1598b9ef 276 struct ifla_vf_vlan ivv;
3fd86630 277 NEXT_ARG();
1598b9ef
SH
278 if (get_unsigned(&ivv.vlan, *argv, 0)) {
279 invarg("Invalid \"vlan\" value\n", *argv);
280 }
281 ivv.vf = vf;
282 ivv.qos = 0;
3fd86630
CW
283 if (NEXT_ARG_OK()) {
284 NEXT_ARG();
285 if (matches(*argv, "qos") == 0) {
286 NEXT_ARG();
1598b9ef
SH
287 if (get_unsigned(&ivv.qos, *argv, 0)) {
288 invarg("Invalid \"qos\" value\n", *argv);
289 }
3fd86630
CW
290 } else {
291 /* rewind arg */
292 PREV_ARG();
293 }
294 }
1598b9ef 295 addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
3fd86630 296 } else if (matches(*argv, "rate") == 0) {
1598b9ef 297 struct ifla_vf_tx_rate ivt;
3fd86630 298 NEXT_ARG();
1598b9ef
SH
299 if (get_unsigned(&ivt.rate, *argv, 0)) {
300 invarg("Invalid \"rate\" value\n", *argv);
301 }
302 ivt.vf = vf;
f89a2a05
SC
303 if (!new_rate_api)
304 addattr_l(&req->n, sizeof(*req),
305 IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
306 else if (!override_legacy_rate)
307 tivt.max_tx_rate = ivt.rate;
308
309 } else if (matches(*argv, "max_tx_rate") == 0) {
310 NEXT_ARG();
311 if (get_unsigned(&tivt.max_tx_rate, *argv, 0))
312 invarg("Invalid \"max tx rate\" value\n",
313 *argv);
314 tivt.vf = vf;
315
316 } else if (matches(*argv, "min_tx_rate") == 0) {
317 NEXT_ARG();
318 if (get_unsigned(&tivt.min_tx_rate, *argv, 0))
319 invarg("Invalid \"min tx rate\" value\n",
320 *argv);
321 tivt.vf = vf;
af89576d 322
7b8179c7
GR
323 } else if (matches(*argv, "spoofchk") == 0) {
324 struct ifla_vf_spoofchk ivs;
325 NEXT_ARG();
326 if (matches(*argv, "on") == 0)
327 ivs.setting = 1;
328 else if (matches(*argv, "off") == 0)
329 ivs.setting = 0;
330 else
331 invarg("Invalid \"spoofchk\" value\n", *argv);
332 ivs.vf = vf;
333 addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
334
6c55c8c4
VZ
335 } else if (matches(*argv, "query_rss") == 0) {
336 struct ifla_vf_rss_query_en ivs;
337 NEXT_ARG();
338 if (matches(*argv, "on") == 0)
339 ivs.setting = 1;
340 else if (matches(*argv, "off") == 0)
341 ivs.setting = 0;
342 else
343 invarg("Invalid \"query_rss\" value\n", *argv);
344 ivs.vf = vf;
345 addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs));
346
07fa9c15
RE
347 } else if (matches(*argv, "state") == 0) {
348 struct ifla_vf_link_state ivl;
349 NEXT_ARG();
350 if (matches(*argv, "auto") == 0)
351 ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
352 else if (matches(*argv, "enable") == 0)
353 ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
354 else if (matches(*argv, "disable") == 0)
355 ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
356 else
357 invarg("Invalid \"state\" value\n", *argv);
358 ivl.vf = vf;
359 addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl));
3fd86630
CW
360 } else {
361 /* rewind arg */
362 PREV_ARG();
363 break;
364 }
365 }
366
f89a2a05
SC
367 if (new_rate_api) {
368 int tmin, tmax;
9a02651a 369
f89a2a05
SC
370 if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
371 ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
372 if (tivt.min_tx_rate == -1)
373 tivt.min_tx_rate = tmin;
374 if (tivt.max_tx_rate == -1)
375 tivt.max_tx_rate = tmax;
376 }
377 addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
378 sizeof(tivt));
379 }
380
3fd86630
CW
381 if (argc == *argcp)
382 incomplete_command();
383
1598b9ef 384 addattr_nest_end(&req->n, vfinfo);
3fd86630
CW
385
386 *argcp = argc;
387 *argvp = argv;
1598b9ef 388 return 0;
3fd86630
CW
389}
390
909dfe2c 391int iplink_parse(int argc, char **argv, struct iplink_req *req,
5e25cf77 392 char **name, char **type, char **link, char **dev, int *group, int *index)
1d934839 393{
909dfe2c
PE
394 int ret, len;
395 char abuf[32];
1d934839
PM
396 int qlen = -1;
397 int mtu = -1;
e2613dc8 398 int netns = -1;
ae7229d5 399 int vf = -1;
d992f3e6
JP
400 int numtxqueues = -1;
401 int numrxqueues = -1;
9a02651a 402 int dev_index = 0;
ccdcbf35 403 int link_netnsid = -1;
1d934839 404
db02608b 405 *group = -1;
909dfe2c 406 ret = argc;
1d934839
PM
407
408 while (argc > 0) {
409 if (strcmp(*argv, "up") == 0) {
909dfe2c
PE
410 req->i.ifi_change |= IFF_UP;
411 req->i.ifi_flags |= IFF_UP;
1d934839 412 } else if (strcmp(*argv, "down") == 0) {
909dfe2c
PE
413 req->i.ifi_change |= IFF_UP;
414 req->i.ifi_flags &= ~IFF_UP;
1d934839
PM
415 } else if (strcmp(*argv, "name") == 0) {
416 NEXT_ARG();
909dfe2c 417 *name = *argv;
5e25cf77
PE
418 } else if (strcmp(*argv, "index") == 0) {
419 NEXT_ARG();
420 *index = atoi(*argv);
3c682146
WC
421 if (*index < 0)
422 invarg("Invalid \"index\" value", *argv);
1d934839
PM
423 } else if (matches(*argv, "link") == 0) {
424 NEXT_ARG();
909dfe2c 425 *link = *argv;
1d934839
PM
426 } else if (matches(*argv, "address") == 0) {
427 NEXT_ARG();
428 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
cb2eb999
AH
429 if (len < 0)
430 return -1;
909dfe2c 431 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
1d934839 432 } else if (matches(*argv, "broadcast") == 0 ||
909dfe2c 433 strcmp(*argv, "brd") == 0) {
1d934839
PM
434 NEXT_ARG();
435 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
cb2eb999
AH
436 if (len < 0)
437 return -1;
909dfe2c 438 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
1d934839 439 } else if (matches(*argv, "txqueuelen") == 0 ||
909dfe2c
PE
440 strcmp(*argv, "qlen") == 0 ||
441 matches(*argv, "txqlen") == 0) {
1d934839
PM
442 NEXT_ARG();
443 if (qlen != -1)
444 duparg("txqueuelen", *argv);
445 if (get_integer(&qlen, *argv, 0))
446 invarg("Invalid \"txqueuelen\" value\n", *argv);
909dfe2c 447 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
1d934839
PM
448 } else if (strcmp(*argv, "mtu") == 0) {
449 NEXT_ARG();
450 if (mtu != -1)
451 duparg("mtu", *argv);
452 if (get_integer(&mtu, *argv, 0))
453 invarg("Invalid \"mtu\" value\n", *argv);
909dfe2c 454 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
4b726cb1
SH
455 } else if (strcmp(*argv, "netns") == 0) {
456 NEXT_ARG();
457 if (netns != -1)
458 duparg("netns", *argv);
c3087c10 459 if ((netns = netns_get_fd(*argv)) >= 0)
0dc34c77
EB
460 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
461 else if (get_integer(&netns, *argv, 0) == 0)
462 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
463 else
4b726cb1 464 invarg("Invalid \"netns\" value\n", *argv);
1d934839
PM
465 } else if (strcmp(*argv, "multicast") == 0) {
466 NEXT_ARG();
909dfe2c 467 req->i.ifi_change |= IFF_MULTICAST;
1d934839 468 if (strcmp(*argv, "on") == 0) {
909dfe2c 469 req->i.ifi_flags |= IFF_MULTICAST;
1d934839 470 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 471 req->i.ifi_flags &= ~IFF_MULTICAST;
1d934839 472 } else
14645ec2 473 return on_off("multicast", *argv);
1d934839
PM
474 } else if (strcmp(*argv, "allmulticast") == 0) {
475 NEXT_ARG();
909dfe2c 476 req->i.ifi_change |= IFF_ALLMULTI;
1d934839 477 if (strcmp(*argv, "on") == 0) {
909dfe2c 478 req->i.ifi_flags |= IFF_ALLMULTI;
1d934839 479 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 480 req->i.ifi_flags &= ~IFF_ALLMULTI;
1d934839 481 } else
14645ec2 482 return on_off("allmulticast", *argv);
1d934839
PM
483 } else if (strcmp(*argv, "promisc") == 0) {
484 NEXT_ARG();
909dfe2c 485 req->i.ifi_change |= IFF_PROMISC;
1d934839 486 if (strcmp(*argv, "on") == 0) {
909dfe2c 487 req->i.ifi_flags |= IFF_PROMISC;
1d934839 488 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 489 req->i.ifi_flags &= ~IFF_PROMISC;
1d934839 490 } else
14645ec2 491 return on_off("promisc", *argv);
1d934839
PM
492 } else if (strcmp(*argv, "trailers") == 0) {
493 NEXT_ARG();
909dfe2c 494 req->i.ifi_change |= IFF_NOTRAILERS;
1d934839 495 if (strcmp(*argv, "off") == 0) {
909dfe2c 496 req->i.ifi_flags |= IFF_NOTRAILERS;
1d934839 497 } else if (strcmp(*argv, "on") == 0) {
909dfe2c 498 req->i.ifi_flags &= ~IFF_NOTRAILERS;
1d934839 499 } else
14645ec2 500 return on_off("trailers", *argv);
1d934839
PM
501 } else if (strcmp(*argv, "arp") == 0) {
502 NEXT_ARG();
909dfe2c 503 req->i.ifi_change |= IFF_NOARP;
1d934839 504 if (strcmp(*argv, "on") == 0) {
909dfe2c 505 req->i.ifi_flags &= ~IFF_NOARP;
1d934839 506 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 507 req->i.ifi_flags |= IFF_NOARP;
1d934839 508 } else
14645ec2 509 return on_off("noarp", *argv);
ae7229d5 510 } else if (strcmp(*argv, "vf") == 0) {
1598b9ef 511 struct rtattr *vflist;
ae7229d5
WM
512 NEXT_ARG();
513 if (get_integer(&vf, *argv, 0)) {
514 invarg("Invalid \"vf\" value\n", *argv);
515 }
1598b9ef
SH
516 vflist = addattr_nest(&req->n, sizeof(*req),
517 IFLA_VFINFO_LIST);
9a02651a
SH
518 if (dev_index == 0)
519 missarg("dev");
520
f89a2a05 521 len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
1598b9ef
SH
522 if (len < 0)
523 return -1;
524 addattr_nest_end(&req->n, vflist);
a1e191b9
JP
525 } else if (matches(*argv, "master") == 0) {
526 int ifindex;
527 NEXT_ARG();
528 ifindex = ll_name_to_index(*argv);
529 if (!ifindex)
530 invarg("Device does not exist\n", *argv);
531 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
532 &ifindex, 4);
533 } else if (matches(*argv, "nomaster") == 0) {
534 int ifindex = 0;
535 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
536 &ifindex, 4);
1d934839
PM
537 } else if (matches(*argv, "dynamic") == 0) {
538 NEXT_ARG();
909dfe2c 539 req->i.ifi_change |= IFF_DYNAMIC;
1d934839 540 if (strcmp(*argv, "on") == 0) {
909dfe2c 541 req->i.ifi_flags |= IFF_DYNAMIC;
1d934839 542 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 543 req->i.ifi_flags &= ~IFF_DYNAMIC;
1d934839 544 } else
14645ec2 545 return on_off("dynamic", *argv);
1d934839
PM
546 } else if (matches(*argv, "type") == 0) {
547 NEXT_ARG();
909dfe2c 548 *type = *argv;
1d934839
PM
549 argc--; argv++;
550 break;
ace9c961
SH
551 } else if (matches(*argv, "alias") == 0) {
552 NEXT_ARG();
553 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
554 *argv, strlen(*argv));
555 argc--; argv++;
556 break;
db02608b
VD
557 } else if (strcmp(*argv, "group") == 0) {
558 NEXT_ARG();
559 if (*group != -1)
560 duparg("group", *argv);
561 if (rtnl_group_a2n(group, *argv))
562 invarg("Invalid \"group\" value\n", *argv);
82499282
SH
563 } else if (strcmp(*argv, "mode") == 0) {
564 int mode;
565 NEXT_ARG();
4ccfb44d 566 mode = get_link_mode(*argv);
82499282
SH
567 if (mode < 0)
568 invarg("Invalid link mode\n", *argv);
569 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
4f2fdd44
SH
570 } else if (strcmp(*argv, "state") == 0) {
571 int state;
572 NEXT_ARG();
573 state = get_operstate(*argv);
574 if (state < 0)
575 invarg("Invalid operstate\n", *argv);
576
577 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
d992f3e6
JP
578 } else if (matches(*argv, "numtxqueues") == 0) {
579 NEXT_ARG();
580 if (numtxqueues != -1)
581 duparg("numtxqueues", *argv);
582 if (get_integer(&numtxqueues, *argv, 0))
583 invarg("Invalid \"numtxqueues\" value\n", *argv);
584 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
585 &numtxqueues, 4);
586 } else if (matches(*argv, "numrxqueues") == 0) {
587 NEXT_ARG();
588 if (numrxqueues != -1)
589 duparg("numrxqueues", *argv);
590 if (get_integer(&numrxqueues, *argv, 0))
591 invarg("Invalid \"numrxqueues\" value\n", *argv);
592 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
593 &numrxqueues, 4);
ff7c2084
JP
594 } else if (matches(*argv, "addrgenmode") == 0) {
595 struct rtattr *afs, *afs6;
596 int mode;
597 NEXT_ARG();
598 mode = get_addr_gen_mode(*argv);
599 if (mode < 0)
600 invarg("Invalid address generation mode\n", *argv);
601 afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
602 afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
603 addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode);
604 addattr_nest_end(&req->n, afs6);
605 addattr_nest_end(&req->n, afs);
ccdcbf35
ND
606 } else if (matches(*argv, "link-netnsid") == 0) {
607 NEXT_ARG();
608 if (link_netnsid != -1)
609 duparg("link-netnsid", *argv);
610 if (get_integer(&link_netnsid, *argv, 0))
611 invarg("Invalid \"link-netnsid\" value\n", *argv);
612 addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
613 link_netnsid);
1d934839 614 } else {
909dfe2c 615 if (strcmp(*argv, "dev") == 0) {
1d934839
PM
616 NEXT_ARG();
617 }
05325552
PM
618 if (matches(*argv, "help") == 0)
619 usage();
909dfe2c 620 if (*dev)
1d934839 621 duparg2("dev", *argv);
909dfe2c 622 *dev = *argv;
f89a2a05 623 dev_index = ll_name_to_index(*dev);
1d934839
PM
624 }
625 argc--; argv++;
626 }
627
909dfe2c
PE
628 return ret - argc;
629}
630
631static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
632{
633 int len;
634 char *dev = NULL;
635 char *name = NULL;
636 char *link = NULL;
637 char *type = NULL;
3c682146 638 int index = -1;
db02608b 639 int group;
909dfe2c
PE
640 struct link_util *lu = NULL;
641 struct iplink_req req;
642 int ret;
643
644 memset(&req, 0, sizeof(req));
645
646 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
647 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
648 req.n.nlmsg_type = cmd;
649 req.i.ifi_family = preferred_family;
650
5e25cf77 651 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group, &index);
909dfe2c
PE
652 if (ret < 0)
653 return ret;
654
655 argc -= ret;
656 argv += ret;
db02608b
VD
657
658 if (group != -1) {
659 if (dev)
660 addattr_l(&req.n, sizeof(req), IFLA_GROUP,
661 &group, sizeof(group));
662 else {
663 if (argc) {
664 fprintf(stderr, "Garbage instead of arguments "
665 "\"%s ...\". Try \"ip link "
666 "help\".\n", *argv);
667 return -1;
668 }
669 if (flags & NLM_F_CREATE) {
670 fprintf(stderr, "group cannot be used when "
671 "creating devices.\n");
672 return -1;
673 }
674
675 req.i.ifi_index = 0;
676 addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
c079e121 677 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
db02608b
VD
678 exit(2);
679 return 0;
680 }
681 }
682
1d934839
PM
683 if (!(flags & NLM_F_CREATE)) {
684 if (!dev) {
685 fprintf(stderr, "Not enough information: \"dev\" "
686 "argument is required.\n");
687 exit(-1);
688 }
3c682146
WC
689 if (cmd == RTM_NEWLINK && index != -1) {
690 fprintf(stderr, "index can be used only when "
691 "creating devices.\n");
692 exit(-1);
693 }
1d934839
PM
694
695 req.i.ifi_index = ll_name_to_index(dev);
696 if (req.i.ifi_index == 0) {
697 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
698 return -1;
699 }
700 } else {
701 /* Allow "ip link add dev" and "ip link add name" */
702 if (!name)
703 name = dev;
704
705 if (link) {
706 int ifindex;
707
708 ifindex = ll_name_to_index(link);
709 if (ifindex == 0) {
710 fprintf(stderr, "Cannot find device \"%s\"\n",
711 link);
712 return -1;
713 }
714 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
715 }
5e25cf77 716
68ac9ab3
AW
717 if (index == -1)
718 req.i.ifi_index = 0;
719 else
720 req.i.ifi_index = index;
1d934839
PM
721 }
722
723 if (name) {
724 len = strlen(name) + 1;
ca78b0e7
PM
725 if (len == 1)
726 invarg("\"\" is not a valid device identifier\n", "name");
1d934839 727 if (len > IFNAMSIZ)
ca78b0e7 728 invarg("\"name\" too long\n", name);
1d934839
PM
729 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
730 }
731
09fa3279 732 if (type) {
a1e2e5fc 733 struct rtattr *linkinfo;
620ddeda
NA
734 char slavebuf[128], *ulinep = strchr(type, '_');
735 int iflatype;
736
a1e2e5fc 737 linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
09fa3279
SH
738 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
739 strlen(type));
740
620ddeda
NA
741 if (ulinep && !strcmp(ulinep, "_slave")) {
742 strncpy(slavebuf, type, sizeof(slavebuf));
743 slavebuf[sizeof(slavebuf) - 1] = '\0';
744 ulinep = strchr(slavebuf, '_');
745 /* check in case it was after sizeof(slavebuf) - 1*/
746 if (ulinep)
747 *ulinep = '\0';
748 lu = get_link_slave_kind(slavebuf);
749 iflatype = IFLA_INFO_SLAVE_DATA;
750 } else {
751 lu = get_link_kind(type);
752 iflatype = IFLA_INFO_DATA;
753 }
09fa3279 754 if (lu && argc) {
a1e2e5fc 755 struct rtattr *data = addattr_nest(&req.n, sizeof(req), iflatype);
09fa3279
SH
756
757 if (lu->parse_opt &&
758 lu->parse_opt(lu, argc, argv, &req.n))
759 return -1;
760
a1e2e5fc 761 addattr_nest_end(&req.n, data);
09fa3279
SH
762 } else if (argc) {
763 if (matches(*argv, "help") == 0)
764 usage();
765 fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
766 "Try \"ip link help\".\n", *argv);
767 return -1;
768 }
a1e2e5fc 769 addattr_nest_end(&req.n, linkinfo);
09fa3279
SH
770 } else if (flags & NLM_F_CREATE) {
771 fprintf(stderr, "Not enough information: \"type\" argument "
772 "is required\n");
773 return -1;
774 }
775
c079e121 776 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
1d934839
PM
777 exit(2);
778
779 return 0;
780}
781
50b9950d
RP
782int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
783{
784 int len;
785 struct iplink_req req;
c079e121
SH
786 struct {
787 struct nlmsghdr n;
788 char buf[16384];
789 } answer;
50b9950d
RP
790
791 memset(&req, 0, sizeof(req));
792
793 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
794 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
795 req.n.nlmsg_type = RTM_GETLINK;
796 req.i.ifi_family = preferred_family;
797
798 if (name) {
799 len = strlen(name) + 1;
800 if (len == 1)
801 invarg("\"\" is not a valid device identifier\n",
802 "name");
803 if (len > IFNAMSIZ)
804 invarg("\"name\" too long\n", name);
805 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
806 }
807 addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
808
c079e121 809 if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
50b9950d
RP
810 return -2;
811
c079e121 812 print_linkinfo(NULL, &answer.n, stdout);
50b9950d
RP
813
814 return 0;
815}
816
1d934839 817#if IPLINK_IOCTL_COMPAT
aba5acdf
SH
818static int get_ctl_fd(void)
819{
820 int s_errno;
821 int fd;
822
823 fd = socket(PF_INET, SOCK_DGRAM, 0);
824 if (fd >= 0)
825 return fd;
826 s_errno = errno;
827 fd = socket(PF_PACKET, SOCK_DGRAM, 0);
828 if (fd >= 0)
829 return fd;
830 fd = socket(PF_INET6, SOCK_DGRAM, 0);
831 if (fd >= 0)
832 return fd;
833 errno = s_errno;
834 perror("Cannot create control socket");
835 return -1;
836}
837
71058eb8 838static int do_chflags(const char *dev, __u32 flags, __u32 mask)
aba5acdf
SH
839{
840 struct ifreq ifr;
841 int fd;
842 int err;
843
71058eb8 844 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
845 fd = get_ctl_fd();
846 if (fd < 0)
847 return -1;
848 err = ioctl(fd, SIOCGIFFLAGS, &ifr);
849 if (err) {
850 perror("SIOCGIFFLAGS");
851 close(fd);
852 return -1;
853 }
854 if ((ifr.ifr_flags^flags)&mask) {
855 ifr.ifr_flags &= ~mask;
856 ifr.ifr_flags |= mask&flags;
857 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
858 if (err)
859 perror("SIOCSIFFLAGS");
860 }
861 close(fd);
862 return err;
863}
864
71058eb8 865static int do_changename(const char *dev, const char *newdev)
aba5acdf
SH
866{
867 struct ifreq ifr;
868 int fd;
869 int err;
870
71058eb8
SH
871 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
872 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
aba5acdf
SH
873 fd = get_ctl_fd();
874 if (fd < 0)
875 return -1;
876 err = ioctl(fd, SIOCSIFNAME, &ifr);
877 if (err) {
878 perror("SIOCSIFNAME");
879 close(fd);
880 return -1;
881 }
882 close(fd);
883 return err;
884}
885
71058eb8 886static int set_qlen(const char *dev, int qlen)
aba5acdf
SH
887{
888 struct ifreq ifr;
889 int s;
890
891 s = get_ctl_fd();
892 if (s < 0)
893 return -1;
894
895 memset(&ifr, 0, sizeof(ifr));
ae665a52
SH
896 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
897 ifr.ifr_qlen = qlen;
aba5acdf
SH
898 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
899 perror("SIOCSIFXQLEN");
900 close(s);
901 return -1;
902 }
903 close(s);
904
ae665a52 905 return 0;
aba5acdf
SH
906}
907
71058eb8 908static int set_mtu(const char *dev, int mtu)
aba5acdf
SH
909{
910 struct ifreq ifr;
911 int s;
912
913 s = get_ctl_fd();
914 if (s < 0)
915 return -1;
916
917 memset(&ifr, 0, sizeof(ifr));
ae665a52
SH
918 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
919 ifr.ifr_mtu = mtu;
aba5acdf
SH
920 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
921 perror("SIOCSIFMTU");
922 close(s);
923 return -1;
924 }
925 close(s);
926
ae665a52 927 return 0;
aba5acdf
SH
928}
929
71058eb8 930static int get_address(const char *dev, int *htype)
aba5acdf
SH
931{
932 struct ifreq ifr;
933 struct sockaddr_ll me;
f332d169 934 socklen_t alen;
aba5acdf
SH
935 int s;
936
937 s = socket(PF_PACKET, SOCK_DGRAM, 0);
ae665a52 938 if (s < 0) {
aba5acdf
SH
939 perror("socket(PF_PACKET)");
940 return -1;
941 }
942
943 memset(&ifr, 0, sizeof(ifr));
71058eb8 944 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
945 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
946 perror("SIOCGIFINDEX");
947 close(s);
948 return -1;
949 }
950
951 memset(&me, 0, sizeof(me));
952 me.sll_family = AF_PACKET;
953 me.sll_ifindex = ifr.ifr_ifindex;
954 me.sll_protocol = htons(ETH_P_LOOP);
955 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
956 perror("bind");
957 close(s);
958 return -1;
959 }
960
961 alen = sizeof(me);
962 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
963 perror("getsockname");
964 close(s);
965 return -1;
966 }
967 close(s);
968 *htype = me.sll_hatype;
969 return me.sll_halen;
970}
971
ae665a52 972static int parse_address(const char *dev, int hatype, int halen,
7b565754 973 char *lla, struct ifreq *ifr)
aba5acdf
SH
974{
975 int alen;
976
977 memset(ifr, 0, sizeof(*ifr));
71058eb8 978 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
979 ifr->ifr_hwaddr.sa_family = hatype;
980 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
981 if (alen < 0)
982 return -1;
983 if (alen != halen) {
984 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
985 return -1;
986 }
ae665a52 987 return 0;
aba5acdf
SH
988}
989
990static int set_address(struct ifreq *ifr, int brd)
991{
992 int s;
993
994 s = get_ctl_fd();
995 if (s < 0)
996 return -1;
997 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
998 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
999 close(s);
1000 return -1;
1001 }
1002 close(s);
ae665a52 1003 return 0;
aba5acdf
SH
1004}
1005
aba5acdf
SH
1006static int do_set(int argc, char **argv)
1007{
1008 char *dev = NULL;
1009 __u32 mask = 0;
1010 __u32 flags = 0;
1011 int qlen = -1;
1012 int mtu = -1;
1013 char *newaddr = NULL;
1014 char *newbrd = NULL;
1015 struct ifreq ifr0, ifr1;
1016 char *newname = NULL;
1017 int htype, halen;
1018
1019 while (argc > 0) {
1020 if (strcmp(*argv, "up") == 0) {
1021 mask |= IFF_UP;
1022 flags |= IFF_UP;
1023 } else if (strcmp(*argv, "down") == 0) {
1024 mask |= IFF_UP;
1025 flags &= ~IFF_UP;
1026 } else if (strcmp(*argv, "name") == 0) {
1027 NEXT_ARG();
1028 newname = *argv;
1029 } else if (matches(*argv, "address") == 0) {
1030 NEXT_ARG();
1031 newaddr = *argv;
1032 } else if (matches(*argv, "broadcast") == 0 ||
1033 strcmp(*argv, "brd") == 0) {
1034 NEXT_ARG();
1035 newbrd = *argv;
1036 } else if (matches(*argv, "txqueuelen") == 0 ||
1037 strcmp(*argv, "qlen") == 0 ||
1038 matches(*argv, "txqlen") == 0) {
1039 NEXT_ARG();
1040 if (qlen != -1)
1041 duparg("txqueuelen", *argv);
1042 if (get_integer(&qlen, *argv, 0))
1043 invarg("Invalid \"txqueuelen\" value\n", *argv);
1044 } else if (strcmp(*argv, "mtu") == 0) {
1045 NEXT_ARG();
1046 if (mtu != -1)
1047 duparg("mtu", *argv);
1048 if (get_integer(&mtu, *argv, 0))
1049 invarg("Invalid \"mtu\" value\n", *argv);
1050 } else if (strcmp(*argv, "multicast") == 0) {
1051 NEXT_ARG();
1052 mask |= IFF_MULTICAST;
1053 if (strcmp(*argv, "on") == 0) {
1054 flags |= IFF_MULTICAST;
1055 } else if (strcmp(*argv, "off") == 0) {
1056 flags &= ~IFF_MULTICAST;
1057 } else
14645ec2 1058 return on_off("multicast", *argv);
d27b1b5b 1059 } else if (strcmp(*argv, "allmulticast") == 0) {
1060 NEXT_ARG();
1061 mask |= IFF_ALLMULTI;
1062 if (strcmp(*argv, "on") == 0) {
1063 flags |= IFF_ALLMULTI;
1064 } else if (strcmp(*argv, "off") == 0) {
1065 flags &= ~IFF_ALLMULTI;
1066 } else
14645ec2 1067 return on_off("allmulticast", *argv);
d27b1b5b 1068 } else if (strcmp(*argv, "promisc") == 0) {
1069 NEXT_ARG();
1070 mask |= IFF_PROMISC;
1071 if (strcmp(*argv, "on") == 0) {
1072 flags |= IFF_PROMISC;
1073 } else if (strcmp(*argv, "off") == 0) {
1074 flags &= ~IFF_PROMISC;
1075 } else
14645ec2 1076 return on_off("promisc", *argv);
d27b1b5b 1077 } else if (strcmp(*argv, "trailers") == 0) {
1078 NEXT_ARG();
1079 mask |= IFF_NOTRAILERS;
1080 if (strcmp(*argv, "off") == 0) {
1081 flags |= IFF_NOTRAILERS;
1082 } else if (strcmp(*argv, "on") == 0) {
1083 flags &= ~IFF_NOTRAILERS;
1084 } else
14645ec2 1085 return on_off("trailers", *argv);
aba5acdf
SH
1086 } else if (strcmp(*argv, "arp") == 0) {
1087 NEXT_ARG();
1088 mask |= IFF_NOARP;
1089 if (strcmp(*argv, "on") == 0) {
1090 flags &= ~IFF_NOARP;
1091 } else if (strcmp(*argv, "off") == 0) {
1092 flags |= IFF_NOARP;
1093 } else
14645ec2 1094 return on_off("noarp", *argv);
aba5acdf
SH
1095 } else if (matches(*argv, "dynamic") == 0) {
1096 NEXT_ARG();
1097 mask |= IFF_DYNAMIC;
1098 if (strcmp(*argv, "on") == 0) {
1099 flags |= IFF_DYNAMIC;
1100 } else if (strcmp(*argv, "off") == 0) {
1101 flags &= ~IFF_DYNAMIC;
1102 } else
14645ec2 1103 return on_off("dynamic", *argv);
aba5acdf 1104 } else {
4b726cb1 1105 if (strcmp(*argv, "dev") == 0) {
aba5acdf
SH
1106 NEXT_ARG();
1107 }
1108 if (matches(*argv, "help") == 0)
1109 usage();
1110 if (dev)
1111 duparg2("dev", *argv);
1112 dev = *argv;
1113 }
1114 argc--; argv++;
1115 }
1116
1117 if (!dev) {
1118 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
1119 exit(-1);
1120 }
1121
1122 if (newaddr || newbrd) {
1123 halen = get_address(dev, &htype);
1124 if (halen < 0)
1125 return -1;
1126 if (newaddr) {
1127 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
1128 return -1;
1129 }
1130 if (newbrd) {
1131 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
ae665a52 1132 return -1;
aba5acdf
SH
1133 }
1134 }
1135
1136 if (newname && strcmp(dev, newname)) {
ca78b0e7
PM
1137 if (strlen(newname) == 0)
1138 invarg("\"\" is not a valid device identifier\n", "name");
aba5acdf
SH
1139 if (do_changename(dev, newname) < 0)
1140 return -1;
1141 dev = newname;
1142 }
ae665a52 1143 if (qlen != -1) {
aba5acdf 1144 if (set_qlen(dev, qlen) < 0)
ae665a52 1145 return -1;
aba5acdf 1146 }
ae665a52 1147 if (mtu != -1) {
aba5acdf 1148 if (set_mtu(dev, mtu) < 0)
ae665a52 1149 return -1;
aba5acdf
SH
1150 }
1151 if (newaddr || newbrd) {
1152 if (newbrd) {
1153 if (set_address(&ifr1, 1) < 0)
ae665a52 1154 return -1;
aba5acdf
SH
1155 }
1156 if (newaddr) {
1157 if (set_address(&ifr0, 0) < 0)
1158 return -1;
1159 }
1160 }
1161 if (mask)
1162 return do_chflags(dev, flags, mask);
1163 return 0;
1164}
1d934839 1165#endif /* IPLINK_IOCTL_COMPAT */
aba5acdf 1166
561e650e 1167static void do_help(int argc, char **argv)
1168{
1169 struct link_util *lu = NULL;
1170
1171 if (argc <= 0) {
1172 usage();
1173 return ;
1174 }
1175
1176 lu = get_link_kind(*argv);
1177
1178 if (lu && lu->print_help)
1179 lu->print_help(lu, argc-1, argv+1, stdout);
1180 else
1181 usage();
1182}
1183
aba5acdf
SH
1184int do_iplink(int argc, char **argv)
1185{
1186 if (argc > 0) {
1d934839
PM
1187 if (iplink_have_newlink()) {
1188 if (matches(*argv, "add") == 0)
1189 return iplink_modify(RTM_NEWLINK,
1190 NLM_F_CREATE|NLM_F_EXCL,
1191 argc-1, argv+1);
1192 if (matches(*argv, "set") == 0 ||
1193 matches(*argv, "change") == 0)
1194 return iplink_modify(RTM_NEWLINK, 0,
1195 argc-1, argv+1);
1196 if (matches(*argv, "replace") == 0)
1197 return iplink_modify(RTM_NEWLINK,
1198 NLM_F_CREATE|NLM_F_REPLACE,
1199 argc-1, argv+1);
1200 if (matches(*argv, "delete") == 0)
1201 return iplink_modify(RTM_DELLINK, 0,
1202 argc-1, argv+1);
1203 } else {
1204#if IPLINK_IOCTL_COMPAT
1205 if (matches(*argv, "set") == 0)
1206 return do_set(argc-1, argv+1);
1207#endif
1208 }
aba5acdf
SH
1209 if (matches(*argv, "show") == 0 ||
1210 matches(*argv, "lst") == 0 ||
1211 matches(*argv, "list") == 0)
1212 return ipaddr_list_link(argc-1, argv+1);
561e650e 1213 if (matches(*argv, "help") == 0) {
1214 do_help(argc-1, argv+1);
1215 return 0;
1216 }
aba5acdf
SH
1217 } else
1218 return ipaddr_list_link(0, NULL);
1219
1220 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
1221 exit(-1);
1222}