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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
20 #include <sys/socket.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>
28 #include <sys/ioctl.h>
29 #include <linux/sockios.h>
34 #include "ip_common.h"
35 #include "namespace.h"
37 #define IPLINK_IOCTL_COMPAT 1
39 #define LIBDIR "/usr/lib"
42 static void usage(void) __attribute__((noreturn
));
43 static int iplink_have_newlink(void);
45 void iplink_usage(void)
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");
60 fprintf(stderr
, "Usage: ip link set DEVICE [ { up | down } ]\n");
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");
80 fprintf(stderr
, " [ rate TXRATE ] ] \n");
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");
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 | geneve }\n");
101 static void usage(void)
106 static int on_off(const char *msg
, const char *realval
)
108 fprintf(stderr
, "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", msg
, realval
);
112 static void *BODY
; /* cached dlopen(NULL) handle */
113 static struct link_util
*linkutil_list
;
115 static struct link_util
*__get_link_kind(const char *id
, bool slave
)
121 for (l
= linkutil_list
; l
; l
= l
->next
)
122 if (strcmp(l
->id
, id
) == 0 &&
126 snprintf(buf
, sizeof(buf
), LIBDIR
"/ip/link_%s.so", id
);
127 dlh
= dlopen(buf
, RTLD_LAZY
);
129 /* look in current binary, only open once */
132 dlh
= BODY
= dlopen(NULL
, RTLD_LAZY
);
139 snprintf(buf
, sizeof(buf
), "%s_slave_link_util", id
);
141 snprintf(buf
, sizeof(buf
), "%s_link_util", id
);
146 l
->next
= linkutil_list
;
151 struct link_util
*get_link_kind(const char *id
)
153 return __get_link_kind(id
, false);
156 struct link_util
*get_link_slave_kind(const char *id
)
158 return __get_link_kind(id
, true);
161 static int get_link_mode(const char *mode
)
163 if (strcasecmp(mode
, "default") == 0)
164 return IF_LINK_MODE_DEFAULT
;
165 if (strcasecmp(mode
, "dormant") == 0)
166 return IF_LINK_MODE_DORMANT
;
170 static int get_addr_gen_mode(const char *mode
)
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
;
179 #if IPLINK_IOCTL_COMPAT
180 static int have_rtnl_newlink
= -1;
182 static int accept_msg(const struct sockaddr_nl
*who
,
183 struct rtnl_ctrl_data
*ctrl
,
184 struct nlmsghdr
*n
, void *arg
)
186 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(n
);
188 if (n
->nlmsg_type
== NLMSG_ERROR
&&
189 (err
->error
== -EOPNOTSUPP
|| err
->error
== -EINVAL
))
190 have_rtnl_newlink
= 0;
192 have_rtnl_newlink
= 1;
196 static int iplink_have_newlink(void)
204 if (have_rtnl_newlink
< 0) {
205 memset(&req
, 0, sizeof(req
));
207 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
208 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|NLM_F_ACK
;
209 req
.n
.nlmsg_type
= RTM_NEWLINK
;
210 req
.i
.ifi_family
= AF_UNSPEC
;
212 if (rtnl_send(&rth
, &req
.n
, req
.n
.nlmsg_len
) < 0) {
213 perror("request send failed");
216 rtnl_listen(&rth
, accept_msg
, NULL
);
218 return have_rtnl_newlink
;
220 #else /* IPLINK_IOCTL_COMPAT */
221 static int iplink_have_newlink(void)
225 #endif /* ! IPLINK_IOCTL_COMPAT */
233 static int iplink_parse_vf(int vf
, int *argcp
, char ***argvp
,
234 struct iplink_req
*req
, int dev_index
)
236 char new_rate_api
= 0, count
= 0, override_legacy_rate
= 0;
237 struct ifla_vf_rate tivt
;
238 int len
, argc
= *argcp
;
239 char **argv
= *argvp
;
240 struct rtattr
*vfinfo
;
242 tivt
.min_tx_rate
= -1;
243 tivt
.max_tx_rate
= -1;
245 vfinfo
= addattr_nest(&req
->n
, sizeof(*req
), IFLA_VF_INFO
);
247 while (NEXT_ARG_OK()) {
250 if (!matches(*argv
, "max_tx_rate")) {
253 /* override legacy rate */
254 override_legacy_rate
= 1;
255 } else if (!matches(*argv
, "min_tx_rate")) {
266 while (NEXT_ARG_OK()) {
268 if (matches(*argv
, "mac") == 0) {
269 struct ifla_vf_mac ivm
;
272 len
= ll_addr_a2n((char *)ivm
.mac
, 32, *argv
);
275 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_MAC
, &ivm
, sizeof(ivm
));
276 } else if (matches(*argv
, "vlan") == 0) {
277 struct ifla_vf_vlan ivv
;
279 if (get_unsigned(&ivv
.vlan
, *argv
, 0)) {
280 invarg("Invalid \"vlan\" value\n", *argv
);
286 if (matches(*argv
, "qos") == 0) {
288 if (get_unsigned(&ivv
.qos
, *argv
, 0)) {
289 invarg("Invalid \"qos\" value\n", *argv
);
296 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_VLAN
, &ivv
, sizeof(ivv
));
297 } else if (matches(*argv
, "rate") == 0) {
298 struct ifla_vf_tx_rate ivt
;
300 if (get_unsigned(&ivt
.rate
, *argv
, 0)) {
301 invarg("Invalid \"rate\" value\n", *argv
);
305 addattr_l(&req
->n
, sizeof(*req
),
306 IFLA_VF_TX_RATE
, &ivt
, sizeof(ivt
));
307 else if (!override_legacy_rate
)
308 tivt
.max_tx_rate
= ivt
.rate
;
310 } else if (matches(*argv
, "max_tx_rate") == 0) {
312 if (get_unsigned(&tivt
.max_tx_rate
, *argv
, 0))
313 invarg("Invalid \"max tx rate\" value\n",
317 } else if (matches(*argv
, "min_tx_rate") == 0) {
319 if (get_unsigned(&tivt
.min_tx_rate
, *argv
, 0))
320 invarg("Invalid \"min tx rate\" value\n",
324 } else if (matches(*argv
, "spoofchk") == 0) {
325 struct ifla_vf_spoofchk ivs
;
327 if (matches(*argv
, "on") == 0)
329 else if (matches(*argv
, "off") == 0)
332 invarg("Invalid \"spoofchk\" value\n", *argv
);
334 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_SPOOFCHK
, &ivs
, sizeof(ivs
));
336 } else if (matches(*argv
, "query_rss") == 0) {
337 struct ifla_vf_rss_query_en ivs
;
339 if (matches(*argv
, "on") == 0)
341 else if (matches(*argv
, "off") == 0)
344 invarg("Invalid \"query_rss\" value\n", *argv
);
346 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_RSS_QUERY_EN
, &ivs
, sizeof(ivs
));
348 } else if (matches(*argv
, "state") == 0) {
349 struct ifla_vf_link_state ivl
;
351 if (matches(*argv
, "auto") == 0)
352 ivl
.link_state
= IFLA_VF_LINK_STATE_AUTO
;
353 else if (matches(*argv
, "enable") == 0)
354 ivl
.link_state
= IFLA_VF_LINK_STATE_ENABLE
;
355 else if (matches(*argv
, "disable") == 0)
356 ivl
.link_state
= IFLA_VF_LINK_STATE_DISABLE
;
358 invarg("Invalid \"state\" value\n", *argv
);
360 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_LINK_STATE
, &ivl
, sizeof(ivl
));
371 if (tivt
.min_tx_rate
== -1 || tivt
.max_tx_rate
== -1) {
372 ipaddr_get_vf_rate(tivt
.vf
, &tmin
, &tmax
, dev_index
);
373 if (tivt
.min_tx_rate
== -1)
374 tivt
.min_tx_rate
= tmin
;
375 if (tivt
.max_tx_rate
== -1)
376 tivt
.max_tx_rate
= tmax
;
378 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_RATE
, &tivt
,
383 incomplete_command();
385 addattr_nest_end(&req
->n
, vfinfo
);
392 int iplink_parse(int argc
, char **argv
, struct iplink_req
*req
,
393 char **name
, char **type
, char **link
, char **dev
, int *group
, int *index
)
401 int numtxqueues
= -1;
402 int numrxqueues
= -1;
404 int link_netnsid
= -1;
410 if (strcmp(*argv
, "up") == 0) {
411 req
->i
.ifi_change
|= IFF_UP
;
412 req
->i
.ifi_flags
|= IFF_UP
;
413 } else if (strcmp(*argv
, "down") == 0) {
414 req
->i
.ifi_change
|= IFF_UP
;
415 req
->i
.ifi_flags
&= ~IFF_UP
;
416 } else if (strcmp(*argv
, "name") == 0) {
419 } else if (strcmp(*argv
, "index") == 0) {
421 *index
= atoi(*argv
);
423 invarg("Invalid \"index\" value", *argv
);
424 } else if (matches(*argv
, "link") == 0) {
427 } else if (matches(*argv
, "address") == 0) {
429 len
= ll_addr_a2n(abuf
, sizeof(abuf
), *argv
);
432 addattr_l(&req
->n
, sizeof(*req
), IFLA_ADDRESS
, abuf
, len
);
433 } else if (matches(*argv
, "broadcast") == 0 ||
434 strcmp(*argv
, "brd") == 0) {
436 len
= ll_addr_a2n(abuf
, sizeof(abuf
), *argv
);
439 addattr_l(&req
->n
, sizeof(*req
), IFLA_BROADCAST
, abuf
, len
);
440 } else if (matches(*argv
, "txqueuelen") == 0 ||
441 strcmp(*argv
, "qlen") == 0 ||
442 matches(*argv
, "txqlen") == 0) {
445 duparg("txqueuelen", *argv
);
446 if (get_integer(&qlen
, *argv
, 0))
447 invarg("Invalid \"txqueuelen\" value\n", *argv
);
448 addattr_l(&req
->n
, sizeof(*req
), IFLA_TXQLEN
, &qlen
, 4);
449 } else if (strcmp(*argv
, "mtu") == 0) {
452 duparg("mtu", *argv
);
453 if (get_integer(&mtu
, *argv
, 0))
454 invarg("Invalid \"mtu\" value\n", *argv
);
455 addattr_l(&req
->n
, sizeof(*req
), IFLA_MTU
, &mtu
, 4);
456 } else if (strcmp(*argv
, "netns") == 0) {
459 duparg("netns", *argv
);
460 if ((netns
= netns_get_fd(*argv
)) >= 0)
461 addattr_l(&req
->n
, sizeof(*req
), IFLA_NET_NS_FD
, &netns
, 4);
462 else if (get_integer(&netns
, *argv
, 0) == 0)
463 addattr_l(&req
->n
, sizeof(*req
), IFLA_NET_NS_PID
, &netns
, 4);
465 invarg("Invalid \"netns\" value\n", *argv
);
466 } else if (strcmp(*argv
, "multicast") == 0) {
468 req
->i
.ifi_change
|= IFF_MULTICAST
;
469 if (strcmp(*argv
, "on") == 0) {
470 req
->i
.ifi_flags
|= IFF_MULTICAST
;
471 } else if (strcmp(*argv
, "off") == 0) {
472 req
->i
.ifi_flags
&= ~IFF_MULTICAST
;
474 return on_off("multicast", *argv
);
475 } else if (strcmp(*argv
, "allmulticast") == 0) {
477 req
->i
.ifi_change
|= IFF_ALLMULTI
;
478 if (strcmp(*argv
, "on") == 0) {
479 req
->i
.ifi_flags
|= IFF_ALLMULTI
;
480 } else if (strcmp(*argv
, "off") == 0) {
481 req
->i
.ifi_flags
&= ~IFF_ALLMULTI
;
483 return on_off("allmulticast", *argv
);
484 } else if (strcmp(*argv
, "promisc") == 0) {
486 req
->i
.ifi_change
|= IFF_PROMISC
;
487 if (strcmp(*argv
, "on") == 0) {
488 req
->i
.ifi_flags
|= IFF_PROMISC
;
489 } else if (strcmp(*argv
, "off") == 0) {
490 req
->i
.ifi_flags
&= ~IFF_PROMISC
;
492 return on_off("promisc", *argv
);
493 } else if (strcmp(*argv
, "trailers") == 0) {
495 req
->i
.ifi_change
|= IFF_NOTRAILERS
;
496 if (strcmp(*argv
, "off") == 0) {
497 req
->i
.ifi_flags
|= IFF_NOTRAILERS
;
498 } else if (strcmp(*argv
, "on") == 0) {
499 req
->i
.ifi_flags
&= ~IFF_NOTRAILERS
;
501 return on_off("trailers", *argv
);
502 } else if (strcmp(*argv
, "arp") == 0) {
504 req
->i
.ifi_change
|= IFF_NOARP
;
505 if (strcmp(*argv
, "on") == 0) {
506 req
->i
.ifi_flags
&= ~IFF_NOARP
;
507 } else if (strcmp(*argv
, "off") == 0) {
508 req
->i
.ifi_flags
|= IFF_NOARP
;
510 return on_off("noarp", *argv
);
511 } else if (strcmp(*argv
, "vf") == 0) {
512 struct rtattr
*vflist
;
514 if (get_integer(&vf
, *argv
, 0)) {
515 invarg("Invalid \"vf\" value\n", *argv
);
517 vflist
= addattr_nest(&req
->n
, sizeof(*req
),
522 len
= iplink_parse_vf(vf
, &argc
, &argv
, req
, dev_index
);
525 addattr_nest_end(&req
->n
, vflist
);
526 } else if (matches(*argv
, "master") == 0) {
529 ifindex
= ll_name_to_index(*argv
);
531 invarg("Device does not exist\n", *argv
);
532 addattr_l(&req
->n
, sizeof(*req
), IFLA_MASTER
,
534 } else if (matches(*argv
, "nomaster") == 0) {
536 addattr_l(&req
->n
, sizeof(*req
), IFLA_MASTER
,
538 } else if (matches(*argv
, "dynamic") == 0) {
540 req
->i
.ifi_change
|= IFF_DYNAMIC
;
541 if (strcmp(*argv
, "on") == 0) {
542 req
->i
.ifi_flags
|= IFF_DYNAMIC
;
543 } else if (strcmp(*argv
, "off") == 0) {
544 req
->i
.ifi_flags
&= ~IFF_DYNAMIC
;
546 return on_off("dynamic", *argv
);
547 } else if (matches(*argv
, "type") == 0) {
552 } else if (matches(*argv
, "alias") == 0) {
554 addattr_l(&req
->n
, sizeof(*req
), IFLA_IFALIAS
,
555 *argv
, strlen(*argv
));
558 } else if (strcmp(*argv
, "group") == 0) {
561 duparg("group", *argv
);
562 if (rtnl_group_a2n(group
, *argv
))
563 invarg("Invalid \"group\" value\n", *argv
);
564 } else if (strcmp(*argv
, "mode") == 0) {
567 mode
= get_link_mode(*argv
);
569 invarg("Invalid link mode\n", *argv
);
570 addattr8(&req
->n
, sizeof(*req
), IFLA_LINKMODE
, mode
);
571 } else if (strcmp(*argv
, "state") == 0) {
574 state
= get_operstate(*argv
);
576 invarg("Invalid operstate\n", *argv
);
578 addattr8(&req
->n
, sizeof(*req
), IFLA_OPERSTATE
, state
);
579 } else if (matches(*argv
, "numtxqueues") == 0) {
581 if (numtxqueues
!= -1)
582 duparg("numtxqueues", *argv
);
583 if (get_integer(&numtxqueues
, *argv
, 0))
584 invarg("Invalid \"numtxqueues\" value\n", *argv
);
585 addattr_l(&req
->n
, sizeof(*req
), IFLA_NUM_TX_QUEUES
,
587 } else if (matches(*argv
, "numrxqueues") == 0) {
589 if (numrxqueues
!= -1)
590 duparg("numrxqueues", *argv
);
591 if (get_integer(&numrxqueues
, *argv
, 0))
592 invarg("Invalid \"numrxqueues\" value\n", *argv
);
593 addattr_l(&req
->n
, sizeof(*req
), IFLA_NUM_RX_QUEUES
,
595 } else if (matches(*argv
, "addrgenmode") == 0) {
596 struct rtattr
*afs
, *afs6
;
599 mode
= get_addr_gen_mode(*argv
);
601 invarg("Invalid address generation mode\n", *argv
);
602 afs
= addattr_nest(&req
->n
, sizeof(*req
), IFLA_AF_SPEC
);
603 afs6
= addattr_nest(&req
->n
, sizeof(*req
), AF_INET6
);
604 addattr8(&req
->n
, sizeof(*req
), IFLA_INET6_ADDR_GEN_MODE
, mode
);
605 addattr_nest_end(&req
->n
, afs6
);
606 addattr_nest_end(&req
->n
, afs
);
607 } else if (matches(*argv
, "link-netnsid") == 0) {
609 if (link_netnsid
!= -1)
610 duparg("link-netnsid", *argv
);
611 if (get_integer(&link_netnsid
, *argv
, 0))
612 invarg("Invalid \"link-netnsid\" value\n", *argv
);
613 addattr32(&req
->n
, sizeof(*req
), IFLA_LINK_NETNSID
,
616 if (strcmp(*argv
, "dev") == 0) {
619 if (matches(*argv
, "help") == 0)
622 duparg2("dev", *argv
);
624 dev_index
= ll_name_to_index(*dev
);
632 static int iplink_modify(int cmd
, unsigned int flags
, int argc
, char **argv
)
641 struct link_util
*lu
= NULL
;
642 struct iplink_req req
;
645 memset(&req
, 0, sizeof(req
));
647 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
648 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
649 req
.n
.nlmsg_type
= cmd
;
650 req
.i
.ifi_family
= preferred_family
;
652 ret
= iplink_parse(argc
, argv
, &req
, &name
, &type
, &link
, &dev
, &group
, &index
);
661 addattr_l(&req
.n
, sizeof(req
), IFLA_GROUP
,
662 &group
, sizeof(group
));
665 fprintf(stderr
, "Garbage instead of arguments "
666 "\"%s ...\". Try \"ip link "
670 if (flags
& NLM_F_CREATE
) {
671 fprintf(stderr
, "group cannot be used when "
672 "creating devices.\n");
677 addattr32(&req
.n
, sizeof(req
), IFLA_GROUP
, group
);
678 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
) < 0)
684 if (!(flags
& NLM_F_CREATE
)) {
686 fprintf(stderr
, "Not enough information: \"dev\" "
687 "argument is required.\n");
690 if (cmd
== RTM_NEWLINK
&& index
!= -1) {
691 fprintf(stderr
, "index can be used only when "
692 "creating devices.\n");
696 req
.i
.ifi_index
= ll_name_to_index(dev
);
697 if (req
.i
.ifi_index
== 0) {
698 fprintf(stderr
, "Cannot find device \"%s\"\n", dev
);
702 /* Allow "ip link add dev" and "ip link add name" */
709 ifindex
= ll_name_to_index(link
);
711 fprintf(stderr
, "Cannot find device \"%s\"\n",
715 addattr_l(&req
.n
, sizeof(req
), IFLA_LINK
, &ifindex
, 4);
721 req
.i
.ifi_index
= index
;
725 len
= strlen(name
) + 1;
727 invarg("\"\" is not a valid device identifier\n", "name");
729 invarg("\"name\" too long\n", name
);
730 addattr_l(&req
.n
, sizeof(req
), IFLA_IFNAME
, name
, len
);
734 struct rtattr
*linkinfo
;
735 char slavebuf
[128], *ulinep
= strchr(type
, '_');
738 linkinfo
= addattr_nest(&req
.n
, sizeof(req
), IFLA_LINKINFO
);
739 addattr_l(&req
.n
, sizeof(req
), IFLA_INFO_KIND
, type
,
742 if (ulinep
&& !strcmp(ulinep
, "_slave")) {
743 strncpy(slavebuf
, type
, sizeof(slavebuf
));
744 slavebuf
[sizeof(slavebuf
) - 1] = '\0';
745 ulinep
= strchr(slavebuf
, '_');
746 /* check in case it was after sizeof(slavebuf) - 1*/
749 lu
= get_link_slave_kind(slavebuf
);
750 iflatype
= IFLA_INFO_SLAVE_DATA
;
752 lu
= get_link_kind(type
);
753 iflatype
= IFLA_INFO_DATA
;
756 struct rtattr
*data
= addattr_nest(&req
.n
, sizeof(req
), iflatype
);
759 lu
->parse_opt(lu
, argc
, argv
, &req
.n
))
762 addattr_nest_end(&req
.n
, data
);
764 if (matches(*argv
, "help") == 0)
766 fprintf(stderr
, "Garbage instead of arguments \"%s ...\". "
767 "Try \"ip link help\".\n", *argv
);
770 addattr_nest_end(&req
.n
, linkinfo
);
771 } else if (flags
& NLM_F_CREATE
) {
772 fprintf(stderr
, "Not enough information: \"type\" argument "
777 if (rtnl_talk(&rth
, &req
.n
, 0, 0, NULL
) < 0)
783 int iplink_get(unsigned int flags
, char *name
, __u32 filt_mask
)
786 struct iplink_req req
;
789 memset(&req
, 0, sizeof(req
));
791 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
792 req
.n
.nlmsg_flags
= NLM_F_REQUEST
|flags
;
793 req
.n
.nlmsg_type
= RTM_GETLINK
;
794 req
.i
.ifi_family
= preferred_family
;
797 len
= strlen(name
) + 1;
799 invarg("\"\" is not a valid device identifier\n",
802 invarg("\"name\" too long\n", name
);
803 addattr_l(&req
.n
, sizeof(req
), IFLA_IFNAME
, name
, len
);
805 addattr32(&req
.n
, sizeof(req
), IFLA_EXT_MASK
, filt_mask
);
807 if (rtnl_talk(&rth
, &req
.n
, 0, 0, (struct nlmsghdr
*)answer
) < 0)
810 print_linkinfo(NULL
, (struct nlmsghdr
*)answer
, stdout
);
815 #if IPLINK_IOCTL_COMPAT
816 static int get_ctl_fd(void)
821 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
825 fd
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
828 fd
= socket(PF_INET6
, SOCK_DGRAM
, 0);
832 perror("Cannot create control socket");
836 static int do_chflags(const char *dev
, __u32 flags
, __u32 mask
)
842 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
846 err
= ioctl(fd
, SIOCGIFFLAGS
, &ifr
);
848 perror("SIOCGIFFLAGS");
852 if ((ifr
.ifr_flags
^flags
)&mask
) {
853 ifr
.ifr_flags
&= ~mask
;
854 ifr
.ifr_flags
|= mask
&flags
;
855 err
= ioctl(fd
, SIOCSIFFLAGS
, &ifr
);
857 perror("SIOCSIFFLAGS");
863 static int do_changename(const char *dev
, const char *newdev
)
869 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
870 strncpy(ifr
.ifr_newname
, newdev
, IFNAMSIZ
);
874 err
= ioctl(fd
, SIOCSIFNAME
, &ifr
);
876 perror("SIOCSIFNAME");
884 static int set_qlen(const char *dev
, int qlen
)
893 memset(&ifr
, 0, sizeof(ifr
));
894 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
896 if (ioctl(s
, SIOCSIFTXQLEN
, &ifr
) < 0) {
897 perror("SIOCSIFXQLEN");
906 static int set_mtu(const char *dev
, int mtu
)
915 memset(&ifr
, 0, sizeof(ifr
));
916 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
918 if (ioctl(s
, SIOCSIFMTU
, &ifr
) < 0) {
919 perror("SIOCSIFMTU");
928 static int get_address(const char *dev
, int *htype
)
931 struct sockaddr_ll me
;
935 s
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
937 perror("socket(PF_PACKET)");
941 memset(&ifr
, 0, sizeof(ifr
));
942 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
943 if (ioctl(s
, SIOCGIFINDEX
, &ifr
) < 0) {
944 perror("SIOCGIFINDEX");
949 memset(&me
, 0, sizeof(me
));
950 me
.sll_family
= AF_PACKET
;
951 me
.sll_ifindex
= ifr
.ifr_ifindex
;
952 me
.sll_protocol
= htons(ETH_P_LOOP
);
953 if (bind(s
, (struct sockaddr
*)&me
, sizeof(me
)) == -1) {
960 if (getsockname(s
, (struct sockaddr
*)&me
, &alen
) == -1) {
961 perror("getsockname");
966 *htype
= me
.sll_hatype
;
970 static int parse_address(const char *dev
, int hatype
, int halen
,
971 char *lla
, struct ifreq
*ifr
)
975 memset(ifr
, 0, sizeof(*ifr
));
976 strncpy(ifr
->ifr_name
, dev
, IFNAMSIZ
);
977 ifr
->ifr_hwaddr
.sa_family
= hatype
;
978 alen
= ll_addr_a2n(ifr
->ifr_hwaddr
.sa_data
, 14, lla
);
982 fprintf(stderr
, "Wrong address (%s) length: expected %d bytes\n", lla
, halen
);
988 static int set_address(struct ifreq
*ifr
, int brd
)
995 if (ioctl(s
, brd
?SIOCSIFHWBROADCAST
:SIOCSIFHWADDR
, ifr
) < 0) {
996 perror(brd
?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
1004 static int do_set(int argc
, char **argv
)
1011 char *newaddr
= NULL
;
1012 char *newbrd
= NULL
;
1013 struct ifreq ifr0
, ifr1
;
1014 char *newname
= NULL
;
1018 if (strcmp(*argv
, "up") == 0) {
1021 } else if (strcmp(*argv
, "down") == 0) {
1024 } else if (strcmp(*argv
, "name") == 0) {
1027 } else if (matches(*argv
, "address") == 0) {
1030 } else if (matches(*argv
, "broadcast") == 0 ||
1031 strcmp(*argv
, "brd") == 0) {
1034 } else if (matches(*argv
, "txqueuelen") == 0 ||
1035 strcmp(*argv
, "qlen") == 0 ||
1036 matches(*argv
, "txqlen") == 0) {
1039 duparg("txqueuelen", *argv
);
1040 if (get_integer(&qlen
, *argv
, 0))
1041 invarg("Invalid \"txqueuelen\" value\n", *argv
);
1042 } else if (strcmp(*argv
, "mtu") == 0) {
1045 duparg("mtu", *argv
);
1046 if (get_integer(&mtu
, *argv
, 0))
1047 invarg("Invalid \"mtu\" value\n", *argv
);
1048 } else if (strcmp(*argv
, "multicast") == 0) {
1050 mask
|= IFF_MULTICAST
;
1051 if (strcmp(*argv
, "on") == 0) {
1052 flags
|= IFF_MULTICAST
;
1053 } else if (strcmp(*argv
, "off") == 0) {
1054 flags
&= ~IFF_MULTICAST
;
1056 return on_off("multicast", *argv
);
1057 } else if (strcmp(*argv
, "allmulticast") == 0) {
1059 mask
|= IFF_ALLMULTI
;
1060 if (strcmp(*argv
, "on") == 0) {
1061 flags
|= IFF_ALLMULTI
;
1062 } else if (strcmp(*argv
, "off") == 0) {
1063 flags
&= ~IFF_ALLMULTI
;
1065 return on_off("allmulticast", *argv
);
1066 } else if (strcmp(*argv
, "promisc") == 0) {
1068 mask
|= IFF_PROMISC
;
1069 if (strcmp(*argv
, "on") == 0) {
1070 flags
|= IFF_PROMISC
;
1071 } else if (strcmp(*argv
, "off") == 0) {
1072 flags
&= ~IFF_PROMISC
;
1074 return on_off("promisc", *argv
);
1075 } else if (strcmp(*argv
, "trailers") == 0) {
1077 mask
|= IFF_NOTRAILERS
;
1078 if (strcmp(*argv
, "off") == 0) {
1079 flags
|= IFF_NOTRAILERS
;
1080 } else if (strcmp(*argv
, "on") == 0) {
1081 flags
&= ~IFF_NOTRAILERS
;
1083 return on_off("trailers", *argv
);
1084 } else if (strcmp(*argv
, "arp") == 0) {
1087 if (strcmp(*argv
, "on") == 0) {
1088 flags
&= ~IFF_NOARP
;
1089 } else if (strcmp(*argv
, "off") == 0) {
1092 return on_off("noarp", *argv
);
1093 } else if (matches(*argv
, "dynamic") == 0) {
1095 mask
|= IFF_DYNAMIC
;
1096 if (strcmp(*argv
, "on") == 0) {
1097 flags
|= IFF_DYNAMIC
;
1098 } else if (strcmp(*argv
, "off") == 0) {
1099 flags
&= ~IFF_DYNAMIC
;
1101 return on_off("dynamic", *argv
);
1103 if (strcmp(*argv
, "dev") == 0) {
1106 if (matches(*argv
, "help") == 0)
1109 duparg2("dev", *argv
);
1116 fprintf(stderr
, "Not enough of information: \"dev\" argument is required.\n");
1120 if (newaddr
|| newbrd
) {
1121 halen
= get_address(dev
, &htype
);
1125 if (parse_address(dev
, htype
, halen
, newaddr
, &ifr0
) < 0)
1129 if (parse_address(dev
, htype
, halen
, newbrd
, &ifr1
) < 0)
1134 if (newname
&& strcmp(dev
, newname
)) {
1135 if (strlen(newname
) == 0)
1136 invarg("\"\" is not a valid device identifier\n", "name");
1137 if (do_changename(dev
, newname
) < 0)
1142 if (set_qlen(dev
, qlen
) < 0)
1146 if (set_mtu(dev
, mtu
) < 0)
1149 if (newaddr
|| newbrd
) {
1151 if (set_address(&ifr1
, 1) < 0)
1155 if (set_address(&ifr0
, 0) < 0)
1160 return do_chflags(dev
, flags
, mask
);
1163 #endif /* IPLINK_IOCTL_COMPAT */
1165 static void do_help(int argc
, char **argv
)
1167 struct link_util
*lu
= NULL
;
1174 lu
= get_link_kind(*argv
);
1176 if (lu
&& lu
->print_help
)
1177 lu
->print_help(lu
, argc
-1, argv
+1, stdout
);
1182 int do_iplink(int argc
, char **argv
)
1185 if (iplink_have_newlink()) {
1186 if (matches(*argv
, "add") == 0)
1187 return iplink_modify(RTM_NEWLINK
,
1188 NLM_F_CREATE
|NLM_F_EXCL
,
1190 if (matches(*argv
, "set") == 0 ||
1191 matches(*argv
, "change") == 0)
1192 return iplink_modify(RTM_NEWLINK
, 0,
1194 if (matches(*argv
, "replace") == 0)
1195 return iplink_modify(RTM_NEWLINK
,
1196 NLM_F_CREATE
|NLM_F_REPLACE
,
1198 if (matches(*argv
, "delete") == 0)
1199 return iplink_modify(RTM_DELLINK
, 0,
1202 #if IPLINK_IOCTL_COMPAT
1203 if (matches(*argv
, "set") == 0)
1204 return do_set(argc
-1, argv
+1);
1207 if (matches(*argv
, "show") == 0 ||
1208 matches(*argv
, "lst") == 0 ||
1209 matches(*argv
, "list") == 0)
1210 return ipaddr_list_link(argc
-1, argv
+1);
1211 if (matches(*argv
, "help") == 0) {
1212 do_help(argc
-1, argv
+1);
1216 return ipaddr_list_link(0, NULL
);
1218 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv
);