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