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