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