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 }\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 nlmsghdr
*n
, void *arg
)
185 struct nlmsgerr
*err
= (struct nlmsgerr
*)NLMSG_DATA(n
);
187 if (n
->nlmsg_type
== NLMSG_ERROR
&&
188 (err
->error
== -EOPNOTSUPP
|| err
->error
== -EINVAL
))
189 have_rtnl_newlink
= 0;
191 have_rtnl_newlink
= 1;
195 static int iplink_have_newlink(void)
203 if (have_rtnl_newlink
< 0) {
204 memset(&req
, 0, sizeof(req
));
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
;
211 if (rtnl_send(&rth
, &req
.n
, req
.n
.nlmsg_len
) < 0) {
212 perror("request send failed");
215 rtnl_listen(&rth
, accept_msg
, NULL
);
217 return have_rtnl_newlink
;
219 #else /* IPLINK_IOCTL_COMPAT */
220 static int iplink_have_newlink(void)
224 #endif /* ! IPLINK_IOCTL_COMPAT */
232 static int iplink_parse_vf(int vf
, int *argcp
, char ***argvp
,
233 struct iplink_req
*req
, int dev_index
)
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
;
241 tivt
.min_tx_rate
= -1;
242 tivt
.max_tx_rate
= -1;
244 vfinfo
= addattr_nest(&req
->n
, sizeof(*req
), IFLA_VF_INFO
);
246 while (NEXT_ARG_OK()) {
249 if (!matches(*argv
, "max_tx_rate")) {
252 /* override legacy rate */
253 override_legacy_rate
= 1;
254 } else if (!matches(*argv
, "min_tx_rate")) {
265 while (NEXT_ARG_OK()) {
267 if (matches(*argv
, "mac") == 0) {
268 struct ifla_vf_mac ivm
;
271 len
= ll_addr_a2n((char *)ivm
.mac
, 32, *argv
);
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
;
278 if (get_unsigned(&ivv
.vlan
, *argv
, 0)) {
279 invarg("Invalid \"vlan\" value\n", *argv
);
285 if (matches(*argv
, "qos") == 0) {
287 if (get_unsigned(&ivv
.qos
, *argv
, 0)) {
288 invarg("Invalid \"qos\" value\n", *argv
);
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
;
299 if (get_unsigned(&ivt
.rate
, *argv
, 0)) {
300 invarg("Invalid \"rate\" value\n", *argv
);
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
;
309 } else if (matches(*argv
, "max_tx_rate") == 0) {
311 if (get_unsigned(&tivt
.max_tx_rate
, *argv
, 0))
312 invarg("Invalid \"max tx rate\" value\n",
316 } else if (matches(*argv
, "min_tx_rate") == 0) {
318 if (get_unsigned(&tivt
.min_tx_rate
, *argv
, 0))
319 invarg("Invalid \"min tx rate\" value\n",
323 } else if (matches(*argv
, "spoofchk") == 0) {
324 struct ifla_vf_spoofchk ivs
;
326 if (matches(*argv
, "on") == 0)
328 else if (matches(*argv
, "off") == 0)
331 invarg("Invalid \"spoofchk\" value\n", *argv
);
333 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_SPOOFCHK
, &ivs
, sizeof(ivs
));
335 } else if (matches(*argv
, "query_rss") == 0) {
336 struct ifla_vf_rss_query_en ivs
;
338 if (matches(*argv
, "on") == 0)
340 else if (matches(*argv
, "off") == 0)
343 invarg("Invalid \"query_rss\" value\n", *argv
);
345 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_RSS_QUERY_EN
, &ivs
, sizeof(ivs
));
347 } else if (matches(*argv
, "state") == 0) {
348 struct ifla_vf_link_state ivl
;
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
;
357 invarg("Invalid \"state\" value\n", *argv
);
359 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_LINK_STATE
, &ivl
, sizeof(ivl
));
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
;
377 addattr_l(&req
->n
, sizeof(*req
), IFLA_VF_RATE
, &tivt
,
382 incomplete_command();
384 addattr_nest_end(&req
->n
, vfinfo
);
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
)
400 int numtxqueues
= -1;
401 int numrxqueues
= -1;
403 int link_netnsid
= -1;
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) {
418 } else if (strcmp(*argv
, "index") == 0) {
420 *index
= atoi(*argv
);
422 invarg("Invalid \"index\" value", *argv
);
423 } else if (matches(*argv
, "link") == 0) {
426 } else if (matches(*argv
, "address") == 0) {
428 len
= ll_addr_a2n(abuf
, sizeof(abuf
), *argv
);
431 addattr_l(&req
->n
, sizeof(*req
), IFLA_ADDRESS
, abuf
, len
);
432 } else if (matches(*argv
, "broadcast") == 0 ||
433 strcmp(*argv
, "brd") == 0) {
435 len
= ll_addr_a2n(abuf
, sizeof(abuf
), *argv
);
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) {
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) {
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) {
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);
464 invarg("Invalid \"netns\" value\n", *argv
);
465 } else if (strcmp(*argv
, "multicast") == 0) {
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
;
473 return on_off("multicast", *argv
);
474 } else if (strcmp(*argv
, "allmulticast") == 0) {
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
;
482 return on_off("allmulticast", *argv
);
483 } else if (strcmp(*argv
, "promisc") == 0) {
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
;
491 return on_off("promisc", *argv
);
492 } else if (strcmp(*argv
, "trailers") == 0) {
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
;
500 return on_off("trailers", *argv
);
501 } else if (strcmp(*argv
, "arp") == 0) {
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
;
509 return on_off("noarp", *argv
);
510 } else if (strcmp(*argv
, "vf") == 0) {
511 struct rtattr
*vflist
;
513 if (get_integer(&vf
, *argv
, 0)) {
514 invarg("Invalid \"vf\" value\n", *argv
);
516 vflist
= addattr_nest(&req
->n
, sizeof(*req
),
521 len
= iplink_parse_vf(vf
, &argc
, &argv
, req
, dev_index
);
524 addattr_nest_end(&req
->n
, vflist
);
525 } else if (matches(*argv
, "master") == 0) {
528 ifindex
= ll_name_to_index(*argv
);
530 invarg("Device does not exist\n", *argv
);
531 addattr_l(&req
->n
, sizeof(*req
), IFLA_MASTER
,
533 } else if (matches(*argv
, "nomaster") == 0) {
535 addattr_l(&req
->n
, sizeof(*req
), IFLA_MASTER
,
537 } else if (matches(*argv
, "dynamic") == 0) {
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
;
545 return on_off("dynamic", *argv
);
546 } else if (matches(*argv
, "type") == 0) {
551 } else if (matches(*argv
, "alias") == 0) {
553 addattr_l(&req
->n
, sizeof(*req
), IFLA_IFALIAS
,
554 *argv
, strlen(*argv
));
557 } else if (strcmp(*argv
, "group") == 0) {
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) {
566 mode
= get_link_mode(*argv
);
568 invarg("Invalid link mode\n", *argv
);
569 addattr8(&req
->n
, sizeof(*req
), IFLA_LINKMODE
, mode
);
570 } else if (strcmp(*argv
, "state") == 0) {
573 state
= get_operstate(*argv
);
575 invarg("Invalid operstate\n", *argv
);
577 addattr8(&req
->n
, sizeof(*req
), IFLA_OPERSTATE
, state
);
578 } else if (matches(*argv
, "numtxqueues") == 0) {
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
,
586 } else if (matches(*argv
, "numrxqueues") == 0) {
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
,
594 } else if (matches(*argv
, "addrgenmode") == 0) {
595 struct rtattr
*afs
, *afs6
;
598 mode
= get_addr_gen_mode(*argv
);
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) {
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
,
615 if (strcmp(*argv
, "dev") == 0) {
618 if (matches(*argv
, "help") == 0)
621 duparg2("dev", *argv
);
623 dev_index
= ll_name_to_index(*dev
);
631 static int iplink_modify(int cmd
, unsigned int flags
, int argc
, char **argv
)
640 struct link_util
*lu
= NULL
;
641 struct iplink_req req
;
644 memset(&req
, 0, sizeof(req
));
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
;
651 ret
= iplink_parse(argc
, argv
, &req
, &name
, &type
, &link
, &dev
, &group
, &index
);
660 addattr_l(&req
.n
, sizeof(req
), IFLA_GROUP
,
661 &group
, sizeof(group
));
664 fprintf(stderr
, "Garbage instead of arguments "
665 "\"%s ...\". Try \"ip link "
669 if (flags
& NLM_F_CREATE
) {
670 fprintf(stderr
, "group cannot be used when "
671 "creating devices.\n");
676 addattr32(&req
.n
, sizeof(req
), IFLA_GROUP
, group
);
677 if (rtnl_talk(&rth
, &req
.n
, NULL
, 0) < 0)
683 if (!(flags
& NLM_F_CREATE
)) {
685 fprintf(stderr
, "Not enough information: \"dev\" "
686 "argument is required.\n");
689 if (cmd
== RTM_NEWLINK
&& index
!= -1) {
690 fprintf(stderr
, "index can be used only when "
691 "creating devices.\n");
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
);
701 /* Allow "ip link add dev" and "ip link add name" */
708 ifindex
= ll_name_to_index(link
);
710 fprintf(stderr
, "Cannot find device \"%s\"\n",
714 addattr_l(&req
.n
, sizeof(req
), IFLA_LINK
, &ifindex
, 4);
720 req
.i
.ifi_index
= index
;
724 len
= strlen(name
) + 1;
726 invarg("\"\" is not a valid device identifier\n", "name");
728 invarg("\"name\" too long\n", name
);
729 addattr_l(&req
.n
, sizeof(req
), IFLA_IFNAME
, name
, len
);
733 struct rtattr
*linkinfo
;
734 char slavebuf
[128], *ulinep
= strchr(type
, '_');
737 linkinfo
= addattr_nest(&req
.n
, sizeof(req
), IFLA_LINKINFO
);
738 addattr_l(&req
.n
, sizeof(req
), IFLA_INFO_KIND
, type
,
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*/
748 lu
= get_link_slave_kind(slavebuf
);
749 iflatype
= IFLA_INFO_SLAVE_DATA
;
751 lu
= get_link_kind(type
);
752 iflatype
= IFLA_INFO_DATA
;
755 struct rtattr
*data
= addattr_nest(&req
.n
, sizeof(req
), iflatype
);
758 lu
->parse_opt(lu
, argc
, argv
, &req
.n
))
761 addattr_nest_end(&req
.n
, data
);
763 if (matches(*argv
, "help") == 0)
765 fprintf(stderr
, "Garbage instead of arguments \"%s ...\". "
766 "Try \"ip link help\".\n", *argv
);
769 addattr_nest_end(&req
.n
, linkinfo
);
770 } else if (flags
& NLM_F_CREATE
) {
771 fprintf(stderr
, "Not enough information: \"type\" argument "
776 if (rtnl_talk(&rth
, &req
.n
, NULL
, 0) < 0)
782 int iplink_get(unsigned int flags
, char *name
, __u32 filt_mask
)
785 struct iplink_req req
;
791 memset(&req
, 0, sizeof(req
));
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
;
799 len
= strlen(name
) + 1;
801 invarg("\"\" is not a valid device identifier\n",
804 invarg("\"name\" too long\n", name
);
805 addattr_l(&req
.n
, sizeof(req
), IFLA_IFNAME
, name
, len
);
807 addattr32(&req
.n
, sizeof(req
), IFLA_EXT_MASK
, filt_mask
);
809 if (rtnl_talk(&rth
, &req
.n
, &answer
.n
, sizeof(answer
)) < 0)
812 print_linkinfo(NULL
, &answer
.n
, stdout
);
817 #if IPLINK_IOCTL_COMPAT
818 static int get_ctl_fd(void)
823 fd
= socket(PF_INET
, SOCK_DGRAM
, 0);
827 fd
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
830 fd
= socket(PF_INET6
, SOCK_DGRAM
, 0);
834 perror("Cannot create control socket");
838 static int do_chflags(const char *dev
, __u32 flags
, __u32 mask
)
844 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
848 err
= ioctl(fd
, SIOCGIFFLAGS
, &ifr
);
850 perror("SIOCGIFFLAGS");
854 if ((ifr
.ifr_flags
^flags
)&mask
) {
855 ifr
.ifr_flags
&= ~mask
;
856 ifr
.ifr_flags
|= mask
&flags
;
857 err
= ioctl(fd
, SIOCSIFFLAGS
, &ifr
);
859 perror("SIOCSIFFLAGS");
865 static int do_changename(const char *dev
, const char *newdev
)
871 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
872 strncpy(ifr
.ifr_newname
, newdev
, IFNAMSIZ
);
876 err
= ioctl(fd
, SIOCSIFNAME
, &ifr
);
878 perror("SIOCSIFNAME");
886 static int set_qlen(const char *dev
, int qlen
)
895 memset(&ifr
, 0, sizeof(ifr
));
896 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
898 if (ioctl(s
, SIOCSIFTXQLEN
, &ifr
) < 0) {
899 perror("SIOCSIFXQLEN");
908 static int set_mtu(const char *dev
, int mtu
)
917 memset(&ifr
, 0, sizeof(ifr
));
918 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
920 if (ioctl(s
, SIOCSIFMTU
, &ifr
) < 0) {
921 perror("SIOCSIFMTU");
930 static int get_address(const char *dev
, int *htype
)
933 struct sockaddr_ll me
;
937 s
= socket(PF_PACKET
, SOCK_DGRAM
, 0);
939 perror("socket(PF_PACKET)");
943 memset(&ifr
, 0, sizeof(ifr
));
944 strncpy(ifr
.ifr_name
, dev
, IFNAMSIZ
);
945 if (ioctl(s
, SIOCGIFINDEX
, &ifr
) < 0) {
946 perror("SIOCGIFINDEX");
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) {
962 if (getsockname(s
, (struct sockaddr
*)&me
, &alen
) == -1) {
963 perror("getsockname");
968 *htype
= me
.sll_hatype
;
972 static int parse_address(const char *dev
, int hatype
, int halen
,
973 char *lla
, struct ifreq
*ifr
)
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
);
984 fprintf(stderr
, "Wrong address (%s) length: expected %d bytes\n", lla
, halen
);
990 static int set_address(struct ifreq
*ifr
, int brd
)
997 if (ioctl(s
, brd
?SIOCSIFHWBROADCAST
:SIOCSIFHWADDR
, ifr
) < 0) {
998 perror(brd
?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
1006 static int do_set(int argc
, char **argv
)
1013 char *newaddr
= NULL
;
1014 char *newbrd
= NULL
;
1015 struct ifreq ifr0
, ifr1
;
1016 char *newname
= NULL
;
1020 if (strcmp(*argv
, "up") == 0) {
1023 } else if (strcmp(*argv
, "down") == 0) {
1026 } else if (strcmp(*argv
, "name") == 0) {
1029 } else if (matches(*argv
, "address") == 0) {
1032 } else if (matches(*argv
, "broadcast") == 0 ||
1033 strcmp(*argv
, "brd") == 0) {
1036 } else if (matches(*argv
, "txqueuelen") == 0 ||
1037 strcmp(*argv
, "qlen") == 0 ||
1038 matches(*argv
, "txqlen") == 0) {
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) {
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) {
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
;
1058 return on_off("multicast", *argv
);
1059 } else if (strcmp(*argv
, "allmulticast") == 0) {
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
;
1067 return on_off("allmulticast", *argv
);
1068 } else if (strcmp(*argv
, "promisc") == 0) {
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
;
1076 return on_off("promisc", *argv
);
1077 } else if (strcmp(*argv
, "trailers") == 0) {
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
;
1085 return on_off("trailers", *argv
);
1086 } else if (strcmp(*argv
, "arp") == 0) {
1089 if (strcmp(*argv
, "on") == 0) {
1090 flags
&= ~IFF_NOARP
;
1091 } else if (strcmp(*argv
, "off") == 0) {
1094 return on_off("noarp", *argv
);
1095 } else if (matches(*argv
, "dynamic") == 0) {
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
;
1103 return on_off("dynamic", *argv
);
1105 if (strcmp(*argv
, "dev") == 0) {
1108 if (matches(*argv
, "help") == 0)
1111 duparg2("dev", *argv
);
1118 fprintf(stderr
, "Not enough of information: \"dev\" argument is required.\n");
1122 if (newaddr
|| newbrd
) {
1123 halen
= get_address(dev
, &htype
);
1127 if (parse_address(dev
, htype
, halen
, newaddr
, &ifr0
) < 0)
1131 if (parse_address(dev
, htype
, halen
, newbrd
, &ifr1
) < 0)
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)
1144 if (set_qlen(dev
, qlen
) < 0)
1148 if (set_mtu(dev
, mtu
) < 0)
1151 if (newaddr
|| newbrd
) {
1153 if (set_address(&ifr1
, 1) < 0)
1157 if (set_address(&ifr0
, 0) < 0)
1162 return do_chflags(dev
, flags
, mask
);
1165 #endif /* IPLINK_IOCTL_COMPAT */
1167 static void do_help(int argc
, char **argv
)
1169 struct link_util
*lu
= NULL
;
1176 lu
= get_link_kind(*argv
);
1178 if (lu
&& lu
->print_help
)
1179 lu
->print_help(lu
, argc
-1, argv
+1, stdout
);
1184 int do_iplink(int argc
, char **argv
)
1187 if (iplink_have_newlink()) {
1188 if (matches(*argv
, "add") == 0)
1189 return iplink_modify(RTM_NEWLINK
,
1190 NLM_F_CREATE
|NLM_F_EXCL
,
1192 if (matches(*argv
, "set") == 0 ||
1193 matches(*argv
, "change") == 0)
1194 return iplink_modify(RTM_NEWLINK
, 0,
1196 if (matches(*argv
, "replace") == 0)
1197 return iplink_modify(RTM_NEWLINK
,
1198 NLM_F_CREATE
|NLM_F_REPLACE
,
1200 if (matches(*argv
, "delete") == 0)
1201 return iplink_modify(RTM_DELLINK
, 0,
1204 #if IPLINK_IOCTL_COMPAT
1205 if (matches(*argv
, "set") == 0)
1206 return do_set(argc
-1, argv
+1);
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);
1218 return ipaddr_list_link(0, NULL
);
1220 fprintf(stderr
, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv
);