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