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