]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink.c
ip: add support of 'ip link type ip6tnl'
[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>
30
31#include "rt_names.h"
32#include "utils.h"
33#include "ip_common.h"
34
1d934839 35#define IPLINK_IOCTL_COMPAT 1
5e3bb534 36#ifndef LIBDIR
5c434a9e 37#define LIBDIR "/usr/lib"
b514b358 38#endif
aba5acdf
SH
39
40static void usage(void) __attribute__((noreturn));
750a405a 41static int iplink_have_newlink(void);
aba5acdf
SH
42
43void iplink_usage(void)
44{
750a405a 45 if (iplink_have_newlink()) {
a22e9295 46 fprintf(stderr, "Usage: ip link add [link DEV] [ name ] NAME\n");
750a405a
SH
47 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
48 fprintf(stderr, " [ address LLADDR ]\n");
49 fprintf(stderr, " [ broadcast LLADDR ]\n");
50 fprintf(stderr, " [ mtu MTU ]\n");
d992f3e6
JP
51 fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n");
52 fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n");
750a405a
SH
53 fprintf(stderr, " type TYPE [ ARGS ]\n");
54 fprintf(stderr, " ip link delete DEV type TYPE [ ARGS ]\n");
55 fprintf(stderr, "\n");
db02608b 56 fprintf(stderr, " ip link set { dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
750a405a
SH
57 } else
58 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
59
60 fprintf(stderr, " [ arp { on | off } ]\n");
61 fprintf(stderr, " [ dynamic { on | off } ]\n");
62 fprintf(stderr, " [ multicast { on | off } ]\n");
63 fprintf(stderr, " [ allmulticast { on | off } ]\n");
64 fprintf(stderr, " [ promisc { on | off } ]\n");
65 fprintf(stderr, " [ trailers { on | off } ]\n");
66 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
67 fprintf(stderr, " [ name NEWNAME ]\n");
68 fprintf(stderr, " [ address LLADDR ]\n");
69 fprintf(stderr, " [ broadcast LLADDR ]\n");
70 fprintf(stderr, " [ mtu MTU ]\n");
71 fprintf(stderr, " [ netns PID ]\n");
0dc34c77 72 fprintf(stderr, " [ netns NAME ]\n");
ace9c961 73 fprintf(stderr, " [ alias NAME ]\n");
ae7229d5
WM
74 fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
75 fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
7b8179c7 76
1598b9ef 77 fprintf(stderr, " [ rate TXRATE ] ] \n");
7b8179c7
GR
78
79 fprintf(stderr, " [ spoofchk { on | off} ] ] \n");
a1e191b9
JP
80 fprintf(stderr, " [ master DEVICE ]\n");
81 fprintf(stderr, " [ nomaster ]\n");
f960c92a 82 fprintf(stderr, " ip link show [ DEVICE | group GROUP ]\n");
750a405a
SH
83
84 if (iplink_have_newlink()) {
85 fprintf(stderr, "\n");
9d0efc10
ND
86 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can |\n");
87 fprintf(stderr, " bridge | ipoib | ip6tnl }\n");
750a405a 88 }
aba5acdf
SH
89 exit(-1);
90}
91
92static void usage(void)
93{
94 iplink_usage();
95}
96
97static int on_off(char *msg)
98{
99 fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
100 return -1;
101}
102
1d934839
PM
103static void *BODY; /* cached dlopen(NULL) handle */
104static struct link_util *linkutil_list;
105
106struct link_util *get_link_kind(const char *id)
107{
108 void *dlh;
109 char buf[256];
110 struct link_util *l;
111
112 for (l = linkutil_list; l; l = l->next)
113 if (strcmp(l->id, id) == 0)
114 return l;
115
5e3bb534 116 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
1d934839
PM
117 dlh = dlopen(buf, RTLD_LAZY);
118 if (dlh == NULL) {
119 /* look in current binary, only open once */
120 dlh = BODY;
121 if (dlh == NULL) {
122 dlh = BODY = dlopen(NULL, RTLD_LAZY);
123 if (dlh == NULL)
124 return NULL;
125 }
126 }
127
128 snprintf(buf, sizeof(buf), "%s_link_util", id);
129 l = dlsym(dlh, buf);
130 if (l == NULL)
131 return NULL;
132
133 l->next = linkutil_list;
134 linkutil_list = l;
135 return l;
136}
137
82499282
SH
138int get_link_mode(const char *mode)
139{
4ccfb44d 140 if (strcasecmp(mode, "default") == 0)
82499282 141 return IF_LINK_MODE_DEFAULT;
4ccfb44d 142 if (strcasecmp(mode, "dormant") == 0)
82499282
SH
143 return IF_LINK_MODE_DORMANT;
144 return -1;
145}
146
1d934839
PM
147#if IPLINK_IOCTL_COMPAT
148static int have_rtnl_newlink = -1;
149
150static int accept_msg(const struct sockaddr_nl *who,
151 struct nlmsghdr *n, void *arg)
152{
153 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
154
66e529f5
PM
155 if (n->nlmsg_type == NLMSG_ERROR &&
156 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
1d934839
PM
157 have_rtnl_newlink = 0;
158 else
159 have_rtnl_newlink = 1;
160 return -1;
161}
162
163static int iplink_have_newlink(void)
164{
165 struct {
166 struct nlmsghdr n;
167 struct ifinfomsg i;
168 char buf[1024];
169 } req;
170
171 if (have_rtnl_newlink < 0) {
172 memset(&req, 0, sizeof(req));
173
174 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
175 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
176 req.n.nlmsg_type = RTM_NEWLINK;
177 req.i.ifi_family = AF_UNSPEC;
178
6cf8398f 179 rtnl_send(&rth, &req.n, req.n.nlmsg_len);
1d934839
PM
180 rtnl_listen(&rth, accept_msg, NULL);
181 }
182 return have_rtnl_newlink;
183}
184#else /* IPLINK_IOCTL_COMPAT */
185static int iplink_have_newlink(void)
186{
187 return 1;
188}
189#endif /* ! IPLINK_IOCTL_COMPAT */
190
909dfe2c
PE
191struct iplink_req {
192 struct nlmsghdr n;
193 struct ifinfomsg i;
194 char buf[1024];
195};
196
1598b9ef
SH
197int iplink_parse_vf(int vf, int *argcp, char ***argvp,
198 struct iplink_req *req)
3fd86630
CW
199{
200 int len, argc = *argcp;
201 char **argv = *argvp;
202 struct rtattr *vfinfo;
1598b9ef
SH
203
204 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
3fd86630
CW
205
206 while (NEXT_ARG_OK()) {
207 NEXT_ARG();
1598b9ef
SH
208 if (matches(*argv, "mac") == 0) {
209 struct ifla_vf_mac ivm;
3fd86630 210 NEXT_ARG();
1598b9ef
SH
211 ivm.vf = vf;
212 len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
213 if (len < 0)
214 return -1;
215 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
3fd86630 216 } else if (matches(*argv, "vlan") == 0) {
1598b9ef 217 struct ifla_vf_vlan ivv;
3fd86630 218 NEXT_ARG();
1598b9ef
SH
219 if (get_unsigned(&ivv.vlan, *argv, 0)) {
220 invarg("Invalid \"vlan\" value\n", *argv);
221 }
222 ivv.vf = vf;
223 ivv.qos = 0;
3fd86630
CW
224 if (NEXT_ARG_OK()) {
225 NEXT_ARG();
226 if (matches(*argv, "qos") == 0) {
227 NEXT_ARG();
1598b9ef
SH
228 if (get_unsigned(&ivv.qos, *argv, 0)) {
229 invarg("Invalid \"qos\" value\n", *argv);
230 }
3fd86630
CW
231 } else {
232 /* rewind arg */
233 PREV_ARG();
234 }
235 }
1598b9ef 236 addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
3fd86630 237 } else if (matches(*argv, "rate") == 0) {
1598b9ef 238 struct ifla_vf_tx_rate ivt;
3fd86630 239 NEXT_ARG();
1598b9ef
SH
240 if (get_unsigned(&ivt.rate, *argv, 0)) {
241 invarg("Invalid \"rate\" value\n", *argv);
242 }
243 ivt.vf = vf;
244 addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
245
7b8179c7
GR
246 } else if (matches(*argv, "spoofchk") == 0) {
247 struct ifla_vf_spoofchk ivs;
248 NEXT_ARG();
249 if (matches(*argv, "on") == 0)
250 ivs.setting = 1;
251 else if (matches(*argv, "off") == 0)
252 ivs.setting = 0;
253 else
254 invarg("Invalid \"spoofchk\" value\n", *argv);
255 ivs.vf = vf;
256 addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
257
3fd86630
CW
258 } else {
259 /* rewind arg */
260 PREV_ARG();
261 break;
262 }
263 }
264
265 if (argc == *argcp)
266 incomplete_command();
267
1598b9ef 268 addattr_nest_end(&req->n, vfinfo);
3fd86630
CW
269
270 *argcp = argc;
271 *argvp = argv;
1598b9ef 272 return 0;
3fd86630
CW
273}
274
275
909dfe2c 276int iplink_parse(int argc, char **argv, struct iplink_req *req,
db02608b 277 char **name, char **type, char **link, char **dev, int *group)
1d934839 278{
909dfe2c
PE
279 int ret, len;
280 char abuf[32];
1d934839
PM
281 int qlen = -1;
282 int mtu = -1;
e2613dc8 283 int netns = -1;
ae7229d5 284 int vf = -1;
d992f3e6
JP
285 int numtxqueues = -1;
286 int numrxqueues = -1;
1d934839 287
db02608b 288 *group = -1;
909dfe2c 289 ret = argc;
1d934839
PM
290
291 while (argc > 0) {
292 if (strcmp(*argv, "up") == 0) {
909dfe2c
PE
293 req->i.ifi_change |= IFF_UP;
294 req->i.ifi_flags |= IFF_UP;
1d934839 295 } else if (strcmp(*argv, "down") == 0) {
909dfe2c
PE
296 req->i.ifi_change |= IFF_UP;
297 req->i.ifi_flags &= ~IFF_UP;
1d934839
PM
298 } else if (strcmp(*argv, "name") == 0) {
299 NEXT_ARG();
909dfe2c 300 *name = *argv;
1d934839
PM
301 } else if (matches(*argv, "link") == 0) {
302 NEXT_ARG();
909dfe2c 303 *link = *argv;
1d934839
PM
304 } else if (matches(*argv, "address") == 0) {
305 NEXT_ARG();
306 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
cb2eb999
AH
307 if (len < 0)
308 return -1;
909dfe2c 309 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
1d934839 310 } else if (matches(*argv, "broadcast") == 0 ||
909dfe2c 311 strcmp(*argv, "brd") == 0) {
1d934839
PM
312 NEXT_ARG();
313 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
cb2eb999
AH
314 if (len < 0)
315 return -1;
909dfe2c 316 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
1d934839 317 } else if (matches(*argv, "txqueuelen") == 0 ||
909dfe2c
PE
318 strcmp(*argv, "qlen") == 0 ||
319 matches(*argv, "txqlen") == 0) {
1d934839
PM
320 NEXT_ARG();
321 if (qlen != -1)
322 duparg("txqueuelen", *argv);
323 if (get_integer(&qlen, *argv, 0))
324 invarg("Invalid \"txqueuelen\" value\n", *argv);
909dfe2c 325 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
1d934839
PM
326 } else if (strcmp(*argv, "mtu") == 0) {
327 NEXT_ARG();
328 if (mtu != -1)
329 duparg("mtu", *argv);
330 if (get_integer(&mtu, *argv, 0))
331 invarg("Invalid \"mtu\" value\n", *argv);
909dfe2c 332 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
e2613dc8
BT
333 } else if (strcmp(*argv, "netns") == 0) {
334 NEXT_ARG();
335 if (netns != -1)
336 duparg("netns", *argv);
0dc34c77
EB
337 if ((netns = get_netns_fd(*argv)) >= 0)
338 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
339 else if (get_integer(&netns, *argv, 0) == 0)
340 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
341 else
e2613dc8 342 invarg("Invalid \"netns\" value\n", *argv);
1d934839
PM
343 } else if (strcmp(*argv, "multicast") == 0) {
344 NEXT_ARG();
909dfe2c 345 req->i.ifi_change |= IFF_MULTICAST;
1d934839 346 if (strcmp(*argv, "on") == 0) {
909dfe2c 347 req->i.ifi_flags |= IFF_MULTICAST;
1d934839 348 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 349 req->i.ifi_flags &= ~IFF_MULTICAST;
1d934839
PM
350 } else
351 return on_off("multicast");
352 } else if (strcmp(*argv, "allmulticast") == 0) {
353 NEXT_ARG();
909dfe2c 354 req->i.ifi_change |= IFF_ALLMULTI;
1d934839 355 if (strcmp(*argv, "on") == 0) {
909dfe2c 356 req->i.ifi_flags |= IFF_ALLMULTI;
1d934839 357 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 358 req->i.ifi_flags &= ~IFF_ALLMULTI;
1d934839
PM
359 } else
360 return on_off("allmulticast");
361 } else if (strcmp(*argv, "promisc") == 0) {
362 NEXT_ARG();
909dfe2c 363 req->i.ifi_change |= IFF_PROMISC;
1d934839 364 if (strcmp(*argv, "on") == 0) {
909dfe2c 365 req->i.ifi_flags |= IFF_PROMISC;
1d934839 366 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 367 req->i.ifi_flags &= ~IFF_PROMISC;
1d934839
PM
368 } else
369 return on_off("promisc");
370 } else if (strcmp(*argv, "trailers") == 0) {
371 NEXT_ARG();
909dfe2c 372 req->i.ifi_change |= IFF_NOTRAILERS;
1d934839 373 if (strcmp(*argv, "off") == 0) {
909dfe2c 374 req->i.ifi_flags |= IFF_NOTRAILERS;
1d934839 375 } else if (strcmp(*argv, "on") == 0) {
909dfe2c 376 req->i.ifi_flags &= ~IFF_NOTRAILERS;
1d934839
PM
377 } else
378 return on_off("trailers");
379 } else if (strcmp(*argv, "arp") == 0) {
380 NEXT_ARG();
909dfe2c 381 req->i.ifi_change |= IFF_NOARP;
1d934839 382 if (strcmp(*argv, "on") == 0) {
909dfe2c 383 req->i.ifi_flags &= ~IFF_NOARP;
1d934839 384 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 385 req->i.ifi_flags |= IFF_NOARP;
1d934839
PM
386 } else
387 return on_off("noarp");
ae7229d5 388 } else if (strcmp(*argv, "vf") == 0) {
1598b9ef 389 struct rtattr *vflist;
ae7229d5
WM
390 NEXT_ARG();
391 if (get_integer(&vf, *argv, 0)) {
392 invarg("Invalid \"vf\" value\n", *argv);
393 }
1598b9ef
SH
394 vflist = addattr_nest(&req->n, sizeof(*req),
395 IFLA_VFINFO_LIST);
396 len = iplink_parse_vf(vf, &argc, &argv, req);
397 if (len < 0)
398 return -1;
399 addattr_nest_end(&req->n, vflist);
a1e191b9
JP
400 } else if (matches(*argv, "master") == 0) {
401 int ifindex;
402 NEXT_ARG();
403 ifindex = ll_name_to_index(*argv);
404 if (!ifindex)
405 invarg("Device does not exist\n", *argv);
406 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
407 &ifindex, 4);
408 } else if (matches(*argv, "nomaster") == 0) {
409 int ifindex = 0;
410 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
411 &ifindex, 4);
1d934839
PM
412 } else if (matches(*argv, "dynamic") == 0) {
413 NEXT_ARG();
909dfe2c 414 req->i.ifi_change |= IFF_DYNAMIC;
1d934839 415 if (strcmp(*argv, "on") == 0) {
909dfe2c 416 req->i.ifi_flags |= IFF_DYNAMIC;
1d934839 417 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 418 req->i.ifi_flags &= ~IFF_DYNAMIC;
1d934839
PM
419 } else
420 return on_off("dynamic");
1d934839
PM
421 } else if (matches(*argv, "type") == 0) {
422 NEXT_ARG();
909dfe2c 423 *type = *argv;
1d934839
PM
424 argc--; argv++;
425 break;
ace9c961
SH
426 } else if (matches(*argv, "alias") == 0) {
427 NEXT_ARG();
428 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
429 *argv, strlen(*argv));
430 argc--; argv++;
431 break;
db02608b
VD
432 } else if (strcmp(*argv, "group") == 0) {
433 NEXT_ARG();
434 if (*group != -1)
435 duparg("group", *argv);
436 if (rtnl_group_a2n(group, *argv))
437 invarg("Invalid \"group\" value\n", *argv);
82499282
SH
438 } else if (strcmp(*argv, "mode") == 0) {
439 int mode;
440 NEXT_ARG();
4ccfb44d 441 mode = get_link_mode(*argv);
82499282
SH
442 if (mode < 0)
443 invarg("Invalid link mode\n", *argv);
444 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
4f2fdd44
SH
445 } else if (strcmp(*argv, "state") == 0) {
446 int state;
447 NEXT_ARG();
448 state = get_operstate(*argv);
449 if (state < 0)
450 invarg("Invalid operstate\n", *argv);
451
452 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
d992f3e6
JP
453 } else if (matches(*argv, "numtxqueues") == 0) {
454 NEXT_ARG();
455 if (numtxqueues != -1)
456 duparg("numtxqueues", *argv);
457 if (get_integer(&numtxqueues, *argv, 0))
458 invarg("Invalid \"numtxqueues\" value\n", *argv);
459 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
460 &numtxqueues, 4);
461 } else if (matches(*argv, "numrxqueues") == 0) {
462 NEXT_ARG();
463 if (numrxqueues != -1)
464 duparg("numrxqueues", *argv);
465 if (get_integer(&numrxqueues, *argv, 0))
466 invarg("Invalid \"numrxqueues\" value\n", *argv);
467 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
468 &numrxqueues, 4);
1d934839 469 } else {
909dfe2c 470 if (strcmp(*argv, "dev") == 0) {
1d934839
PM
471 NEXT_ARG();
472 }
05325552
PM
473 if (matches(*argv, "help") == 0)
474 usage();
909dfe2c 475 if (*dev)
1d934839 476 duparg2("dev", *argv);
909dfe2c 477 *dev = *argv;
1d934839
PM
478 }
479 argc--; argv++;
480 }
481
909dfe2c
PE
482 return ret - argc;
483}
484
485static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
486{
487 int len;
488 char *dev = NULL;
489 char *name = NULL;
490 char *link = NULL;
491 char *type = NULL;
db02608b 492 int group;
909dfe2c
PE
493 struct link_util *lu = NULL;
494 struct iplink_req req;
495 int ret;
496
497 memset(&req, 0, sizeof(req));
498
499 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
500 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
501 req.n.nlmsg_type = cmd;
502 req.i.ifi_family = preferred_family;
503
db02608b 504 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group);
909dfe2c
PE
505 if (ret < 0)
506 return ret;
507
508 argc -= ret;
509 argv += ret;
db02608b
VD
510
511 if (group != -1) {
512 if (dev)
513 addattr_l(&req.n, sizeof(req), IFLA_GROUP,
514 &group, sizeof(group));
515 else {
516 if (argc) {
517 fprintf(stderr, "Garbage instead of arguments "
518 "\"%s ...\". Try \"ip link "
519 "help\".\n", *argv);
520 return -1;
521 }
522 if (flags & NLM_F_CREATE) {
523 fprintf(stderr, "group cannot be used when "
524 "creating devices.\n");
525 return -1;
526 }
527
528 req.i.ifi_index = 0;
529 addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
cd70f3f5 530 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
db02608b
VD
531 exit(2);
532 return 0;
533 }
534 }
535
1d934839
PM
536 ll_init_map(&rth);
537
1d934839
PM
538 if (!(flags & NLM_F_CREATE)) {
539 if (!dev) {
540 fprintf(stderr, "Not enough information: \"dev\" "
541 "argument is required.\n");
542 exit(-1);
543 }
544
545 req.i.ifi_index = ll_name_to_index(dev);
546 if (req.i.ifi_index == 0) {
547 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
548 return -1;
549 }
550 } else {
551 /* Allow "ip link add dev" and "ip link add name" */
552 if (!name)
553 name = dev;
554
555 if (link) {
556 int ifindex;
557
558 ifindex = ll_name_to_index(link);
559 if (ifindex == 0) {
560 fprintf(stderr, "Cannot find device \"%s\"\n",
561 link);
562 return -1;
563 }
564 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
565 }
566 }
567
568 if (name) {
569 len = strlen(name) + 1;
ca78b0e7
PM
570 if (len == 1)
571 invarg("\"\" is not a valid device identifier\n", "name");
1d934839 572 if (len > IFNAMSIZ)
ca78b0e7 573 invarg("\"name\" too long\n", name);
1d934839
PM
574 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
575 }
576
09fa3279
SH
577 if (type) {
578 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
579 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
580 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
581 strlen(type));
582
583 lu = get_link_kind(type);
584 if (lu && argc) {
585 struct rtattr * data = NLMSG_TAIL(&req.n);
586 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
587
588 if (lu->parse_opt &&
589 lu->parse_opt(lu, argc, argv, &req.n))
590 return -1;
591
592 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
593 } else if (argc) {
594 if (matches(*argv, "help") == 0)
595 usage();
596 fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
597 "Try \"ip link help\".\n", *argv);
598 return -1;
599 }
600 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
601 } else if (flags & NLM_F_CREATE) {
602 fprintf(stderr, "Not enough information: \"type\" argument "
603 "is required\n");
604 return -1;
605 }
606
cd70f3f5 607 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
1d934839
PM
608 exit(2);
609
610 return 0;
611}
612
613#if IPLINK_IOCTL_COMPAT
aba5acdf
SH
614static int get_ctl_fd(void)
615{
616 int s_errno;
617 int fd;
618
619 fd = socket(PF_INET, SOCK_DGRAM, 0);
620 if (fd >= 0)
621 return fd;
622 s_errno = errno;
623 fd = socket(PF_PACKET, SOCK_DGRAM, 0);
624 if (fd >= 0)
625 return fd;
626 fd = socket(PF_INET6, SOCK_DGRAM, 0);
627 if (fd >= 0)
628 return fd;
629 errno = s_errno;
630 perror("Cannot create control socket");
631 return -1;
632}
633
71058eb8 634static int do_chflags(const char *dev, __u32 flags, __u32 mask)
aba5acdf
SH
635{
636 struct ifreq ifr;
637 int fd;
638 int err;
639
71058eb8 640 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
641 fd = get_ctl_fd();
642 if (fd < 0)
643 return -1;
644 err = ioctl(fd, SIOCGIFFLAGS, &ifr);
645 if (err) {
646 perror("SIOCGIFFLAGS");
647 close(fd);
648 return -1;
649 }
650 if ((ifr.ifr_flags^flags)&mask) {
651 ifr.ifr_flags &= ~mask;
652 ifr.ifr_flags |= mask&flags;
653 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
654 if (err)
655 perror("SIOCSIFFLAGS");
656 }
657 close(fd);
658 return err;
659}
660
71058eb8 661static int do_changename(const char *dev, const char *newdev)
aba5acdf
SH
662{
663 struct ifreq ifr;
664 int fd;
665 int err;
666
71058eb8
SH
667 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
668 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
aba5acdf
SH
669 fd = get_ctl_fd();
670 if (fd < 0)
671 return -1;
672 err = ioctl(fd, SIOCSIFNAME, &ifr);
673 if (err) {
674 perror("SIOCSIFNAME");
675 close(fd);
676 return -1;
677 }
678 close(fd);
679 return err;
680}
681
71058eb8 682static int set_qlen(const char *dev, int qlen)
aba5acdf
SH
683{
684 struct ifreq ifr;
685 int s;
686
687 s = get_ctl_fd();
688 if (s < 0)
689 return -1;
690
691 memset(&ifr, 0, sizeof(ifr));
ae665a52
SH
692 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
693 ifr.ifr_qlen = qlen;
aba5acdf
SH
694 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
695 perror("SIOCSIFXQLEN");
696 close(s);
697 return -1;
698 }
699 close(s);
700
ae665a52 701 return 0;
aba5acdf
SH
702}
703
71058eb8 704static int set_mtu(const char *dev, int mtu)
aba5acdf
SH
705{
706 struct ifreq ifr;
707 int s;
708
709 s = get_ctl_fd();
710 if (s < 0)
711 return -1;
712
713 memset(&ifr, 0, sizeof(ifr));
ae665a52
SH
714 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
715 ifr.ifr_mtu = mtu;
aba5acdf
SH
716 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
717 perror("SIOCSIFMTU");
718 close(s);
719 return -1;
720 }
721 close(s);
722
ae665a52 723 return 0;
aba5acdf
SH
724}
725
71058eb8 726static int get_address(const char *dev, int *htype)
aba5acdf
SH
727{
728 struct ifreq ifr;
729 struct sockaddr_ll me;
f332d169 730 socklen_t alen;
aba5acdf
SH
731 int s;
732
733 s = socket(PF_PACKET, SOCK_DGRAM, 0);
ae665a52 734 if (s < 0) {
aba5acdf
SH
735 perror("socket(PF_PACKET)");
736 return -1;
737 }
738
739 memset(&ifr, 0, sizeof(ifr));
71058eb8 740 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
741 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
742 perror("SIOCGIFINDEX");
743 close(s);
744 return -1;
745 }
746
747 memset(&me, 0, sizeof(me));
748 me.sll_family = AF_PACKET;
749 me.sll_ifindex = ifr.ifr_ifindex;
750 me.sll_protocol = htons(ETH_P_LOOP);
751 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
752 perror("bind");
753 close(s);
754 return -1;
755 }
756
757 alen = sizeof(me);
758 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
759 perror("getsockname");
760 close(s);
761 return -1;
762 }
763 close(s);
764 *htype = me.sll_hatype;
765 return me.sll_halen;
766}
767
ae665a52 768static int parse_address(const char *dev, int hatype, int halen,
7b565754 769 char *lla, struct ifreq *ifr)
aba5acdf
SH
770{
771 int alen;
772
773 memset(ifr, 0, sizeof(*ifr));
71058eb8 774 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
775 ifr->ifr_hwaddr.sa_family = hatype;
776 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
777 if (alen < 0)
778 return -1;
779 if (alen != halen) {
780 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
781 return -1;
782 }
ae665a52 783 return 0;
aba5acdf
SH
784}
785
786static int set_address(struct ifreq *ifr, int brd)
787{
788 int s;
789
790 s = get_ctl_fd();
791 if (s < 0)
792 return -1;
793 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
794 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
795 close(s);
796 return -1;
797 }
798 close(s);
ae665a52 799 return 0;
aba5acdf
SH
800}
801
802
803static int do_set(int argc, char **argv)
804{
805 char *dev = NULL;
806 __u32 mask = 0;
807 __u32 flags = 0;
808 int qlen = -1;
809 int mtu = -1;
810 char *newaddr = NULL;
811 char *newbrd = NULL;
812 struct ifreq ifr0, ifr1;
813 char *newname = NULL;
814 int htype, halen;
815
816 while (argc > 0) {
817 if (strcmp(*argv, "up") == 0) {
818 mask |= IFF_UP;
819 flags |= IFF_UP;
820 } else if (strcmp(*argv, "down") == 0) {
821 mask |= IFF_UP;
822 flags &= ~IFF_UP;
823 } else if (strcmp(*argv, "name") == 0) {
824 NEXT_ARG();
825 newname = *argv;
826 } else if (matches(*argv, "address") == 0) {
827 NEXT_ARG();
828 newaddr = *argv;
829 } else if (matches(*argv, "broadcast") == 0 ||
830 strcmp(*argv, "brd") == 0) {
831 NEXT_ARG();
832 newbrd = *argv;
833 } else if (matches(*argv, "txqueuelen") == 0 ||
834 strcmp(*argv, "qlen") == 0 ||
835 matches(*argv, "txqlen") == 0) {
836 NEXT_ARG();
837 if (qlen != -1)
838 duparg("txqueuelen", *argv);
839 if (get_integer(&qlen, *argv, 0))
840 invarg("Invalid \"txqueuelen\" value\n", *argv);
841 } else if (strcmp(*argv, "mtu") == 0) {
842 NEXT_ARG();
843 if (mtu != -1)
844 duparg("mtu", *argv);
845 if (get_integer(&mtu, *argv, 0))
846 invarg("Invalid \"mtu\" value\n", *argv);
847 } else if (strcmp(*argv, "multicast") == 0) {
848 NEXT_ARG();
849 mask |= IFF_MULTICAST;
850 if (strcmp(*argv, "on") == 0) {
851 flags |= IFF_MULTICAST;
852 } else if (strcmp(*argv, "off") == 0) {
853 flags &= ~IFF_MULTICAST;
854 } else
855 return on_off("multicast");
d27b1b5b 856 } else if (strcmp(*argv, "allmulticast") == 0) {
857 NEXT_ARG();
858 mask |= IFF_ALLMULTI;
859 if (strcmp(*argv, "on") == 0) {
860 flags |= IFF_ALLMULTI;
861 } else if (strcmp(*argv, "off") == 0) {
862 flags &= ~IFF_ALLMULTI;
863 } else
864 return on_off("allmulticast");
865 } else if (strcmp(*argv, "promisc") == 0) {
866 NEXT_ARG();
867 mask |= IFF_PROMISC;
868 if (strcmp(*argv, "on") == 0) {
869 flags |= IFF_PROMISC;
870 } else if (strcmp(*argv, "off") == 0) {
871 flags &= ~IFF_PROMISC;
872 } else
873 return on_off("promisc");
874 } else if (strcmp(*argv, "trailers") == 0) {
875 NEXT_ARG();
876 mask |= IFF_NOTRAILERS;
877 if (strcmp(*argv, "off") == 0) {
878 flags |= IFF_NOTRAILERS;
879 } else if (strcmp(*argv, "on") == 0) {
880 flags &= ~IFF_NOTRAILERS;
881 } else
882 return on_off("trailers");
aba5acdf
SH
883 } else if (strcmp(*argv, "arp") == 0) {
884 NEXT_ARG();
885 mask |= IFF_NOARP;
886 if (strcmp(*argv, "on") == 0) {
887 flags &= ~IFF_NOARP;
888 } else if (strcmp(*argv, "off") == 0) {
889 flags |= IFF_NOARP;
890 } else
891 return on_off("noarp");
aba5acdf
SH
892 } else if (matches(*argv, "dynamic") == 0) {
893 NEXT_ARG();
894 mask |= IFF_DYNAMIC;
895 if (strcmp(*argv, "on") == 0) {
896 flags |= IFF_DYNAMIC;
897 } else if (strcmp(*argv, "off") == 0) {
898 flags &= ~IFF_DYNAMIC;
899 } else
900 return on_off("dynamic");
aba5acdf
SH
901 } else {
902 if (strcmp(*argv, "dev") == 0) {
903 NEXT_ARG();
904 }
905 if (matches(*argv, "help") == 0)
906 usage();
907 if (dev)
908 duparg2("dev", *argv);
909 dev = *argv;
910 }
911 argc--; argv++;
912 }
913
914 if (!dev) {
915 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
916 exit(-1);
917 }
918
919 if (newaddr || newbrd) {
920 halen = get_address(dev, &htype);
921 if (halen < 0)
922 return -1;
923 if (newaddr) {
924 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
925 return -1;
926 }
927 if (newbrd) {
928 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
ae665a52 929 return -1;
aba5acdf
SH
930 }
931 }
932
933 if (newname && strcmp(dev, newname)) {
ca78b0e7
PM
934 if (strlen(newname) == 0)
935 invarg("\"\" is not a valid device identifier\n", "name");
aba5acdf
SH
936 if (do_changename(dev, newname) < 0)
937 return -1;
938 dev = newname;
939 }
ae665a52 940 if (qlen != -1) {
aba5acdf 941 if (set_qlen(dev, qlen) < 0)
ae665a52 942 return -1;
aba5acdf 943 }
ae665a52 944 if (mtu != -1) {
aba5acdf 945 if (set_mtu(dev, mtu) < 0)
ae665a52 946 return -1;
aba5acdf
SH
947 }
948 if (newaddr || newbrd) {
949 if (newbrd) {
950 if (set_address(&ifr1, 1) < 0)
ae665a52 951 return -1;
aba5acdf
SH
952 }
953 if (newaddr) {
954 if (set_address(&ifr0, 0) < 0)
955 return -1;
956 }
957 }
958 if (mask)
959 return do_chflags(dev, flags, mask);
960 return 0;
961}
1d934839 962#endif /* IPLINK_IOCTL_COMPAT */
aba5acdf
SH
963
964int do_iplink(int argc, char **argv)
965{
966 if (argc > 0) {
1d934839
PM
967 if (iplink_have_newlink()) {
968 if (matches(*argv, "add") == 0)
969 return iplink_modify(RTM_NEWLINK,
970 NLM_F_CREATE|NLM_F_EXCL,
971 argc-1, argv+1);
972 if (matches(*argv, "set") == 0 ||
973 matches(*argv, "change") == 0)
974 return iplink_modify(RTM_NEWLINK, 0,
975 argc-1, argv+1);
976 if (matches(*argv, "replace") == 0)
977 return iplink_modify(RTM_NEWLINK,
978 NLM_F_CREATE|NLM_F_REPLACE,
979 argc-1, argv+1);
980 if (matches(*argv, "delete") == 0)
981 return iplink_modify(RTM_DELLINK, 0,
982 argc-1, argv+1);
983 } else {
984#if IPLINK_IOCTL_COMPAT
985 if (matches(*argv, "set") == 0)
986 return do_set(argc-1, argv+1);
987#endif
988 }
aba5acdf
SH
989 if (matches(*argv, "show") == 0 ||
990 matches(*argv, "lst") == 0 ||
991 matches(*argv, "list") == 0)
992 return ipaddr_list_link(argc-1, argv+1);
993 if (matches(*argv, "help") == 0)
994 usage();
995 } else
996 return ipaddr_list_link(0, NULL);
997
998 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
999 exit(-1);
1000}