blob: 5609cc95bf0e9c17018573677f23e52c2a3f5f63 [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
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>
Patrick McHardy1d934832007-08-22 10:49:01 -070018#include <dlfcn.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000019#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>
Jiri Pirkofbea6112014-01-23 17:52:53 +010030#include <stdbool.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000031
32#include "rt_names.h"
33#include "utils.h"
34#include "ip_common.h"
Vadim Kochanc3087c12015-01-13 22:08:44 +020035#include "namespace.h"
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000036
Patrick McHardy1d934832007-08-22 10:49:01 -070037#define IPLINK_IOCTL_COMPAT 1
Andreas Henriksson5e3bb532008-08-22 16:54:12 +020038#ifndef LIBDIR
Christoph J. Thompson5c434a92012-03-01 17:46:26 +010039#define LIBDIR "/usr/lib"
Rafael Almeidab514b352008-06-01 21:33:44 -030040#endif
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000041
42static void usage(void) __attribute__((noreturn));
Stephen Hemminger750a4052008-10-13 07:17:08 -070043static int iplink_have_newlink(void);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000044
45void iplink_usage(void)
46{
Stephen Hemminger750a4052008-10-13 07:17:08 -070047 if (iplink_have_newlink()) {
Sridhar Samudralaa22e9292011-10-06 16:10:51 -070048 fprintf(stderr, "Usage: ip link add [link DEV] [ name ] NAME\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070049 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
50 fprintf(stderr, " [ address LLADDR ]\n");
51 fprintf(stderr, " [ broadcast LLADDR ]\n");
Pavel Emelyanov5e25cf72013-12-26 23:15:20 +040052 fprintf(stderr, " [ mtu MTU ] [index IDX ]\n");
Jiri Pirkod992f3e2012-08-01 16:19:55 -070053 fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n");
54 fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070055 fprintf(stderr, " type TYPE [ ARGS ]\n");
Vadim Kochan8916ccf2015-05-01 22:26:52 +030056 fprintf(stderr, " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070057 fprintf(stderr, "\n");
Phil Sutter771a2422016-07-09 11:22:45 +020058 fprintf(stderr, " ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n");
59 fprintf(stderr, " [ { up | down } ]\n");
60 fprintf(stderr, " [ type TYPE ARGS ]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070061 } else
62 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
63
64 fprintf(stderr, " [ arp { on | off } ]\n");
65 fprintf(stderr, " [ dynamic { on | off } ]\n");
66 fprintf(stderr, " [ multicast { on | off } ]\n");
67 fprintf(stderr, " [ allmulticast { on | off } ]\n");
68 fprintf(stderr, " [ promisc { on | off } ]\n");
69 fprintf(stderr, " [ trailers { on | off } ]\n");
70 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
71 fprintf(stderr, " [ name NEWNAME ]\n");
72 fprintf(stderr, " [ address LLADDR ]\n");
73 fprintf(stderr, " [ broadcast LLADDR ]\n");
74 fprintf(stderr, " [ mtu MTU ]\n");
Phil Sutter5c2ea5b2016-03-02 19:19:51 +010075 fprintf(stderr, " [ netns { PID | NAME } ]\n");
Vadim Kochan21107f52015-04-04 17:06:19 +030076 fprintf(stderr, " [ link-netnsid ID ]\n");
Stephen Hemmingerace9c962009-03-23 10:46:47 -070077 fprintf(stderr, " [ alias NAME ]\n");
Williams, Mitch Aae7229d2010-02-10 01:47:08 +000078 fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
79 fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
Greg Rose7b8179c2011-10-13 20:31:32 +000080
Phil Sutter5c2ea5b2016-03-02 19:19:51 +010081 fprintf(stderr, " [ rate TXRATE ]\n");
Greg Rose7b8179c2011-10-13 20:31:32 +000082
Phil Sutter5c2ea5b2016-03-02 19:19:51 +010083 fprintf(stderr, " [ spoofchk { on | off} ]\n");
84 fprintf(stderr, " [ query_rss { on | off} ]\n");
Rony Efraim07fa9c12013-06-13 13:19:12 +030085 fprintf(stderr, " [ state { auto | enable | disable} ] ]\n");
Hiroshi Shimamotob6d77d92016-02-26 02:40:18 +000086 fprintf(stderr, " [ trust { on | off} ] ]\n");
David Ahern104444c2016-06-29 11:26:58 -070087 fprintf(stderr, " [ master DEVICE ][ vrf NAME ]\n");
Jiri Pirkoa1e191b2011-02-25 19:55:19 -080088 fprintf(stderr, " [ nomaster ]\n");
Bjørn Mork8e12bc02016-01-04 10:58:05 +010089 fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret | random } ]\n");
Anuradha Karuppiah18864822015-07-14 13:43:22 -070090 fprintf(stderr, " [ protodown { on | off } ]\n");
David Ahern104444c2016-06-29 11:26:58 -070091 fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070092
93 if (iplink_have_newlink()) {
vadimk561e6502014-09-30 08:17:31 +030094 fprintf(stderr, " ip link help [ TYPE ]\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -070095 fprintf(stderr, "\n");
Nicolas Dichtel1253a102013-10-08 07:59:45 -070096 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n");
Oliver Hartkopp2b70fe12014-05-15 19:52:19 +020097 fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n");
Nikolay Aleksandrov620dded2014-09-03 17:57:30 +020098 fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n");
David Ahern15faa0a2015-08-13 14:59:11 -060099 fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf }\n");
Stephen Hemminger750a4052008-10-13 07:17:08 -0700100 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000101 exit(-1);
102}
103
104static void usage(void)
105{
106 iplink_usage();
107}
108
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000109static int on_off(const char *msg, const char *realval)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000110{
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700111 fprintf(stderr,
112 "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n",
113 msg, realval);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000114 return -1;
115}
116
Patrick McHardy1d934832007-08-22 10:49:01 -0700117static void *BODY; /* cached dlopen(NULL) handle */
118static struct link_util *linkutil_list;
119
Jiri Pirkofbea6112014-01-23 17:52:53 +0100120static struct link_util *__get_link_kind(const char *id, bool slave)
Patrick McHardy1d934832007-08-22 10:49:01 -0700121{
122 void *dlh;
123 char buf[256];
124 struct link_util *l;
125
126 for (l = linkutil_list; l; l = l->next)
Jiri Pirkofbea6112014-01-23 17:52:53 +0100127 if (strcmp(l->id, id) == 0 &&
128 l->slave == slave)
Patrick McHardy1d934832007-08-22 10:49:01 -0700129 return l;
130
Andreas Henriksson5e3bb532008-08-22 16:54:12 +0200131 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
Patrick McHardy1d934832007-08-22 10:49:01 -0700132 dlh = dlopen(buf, RTLD_LAZY);
133 if (dlh == NULL) {
134 /* look in current binary, only open once */
135 dlh = BODY;
136 if (dlh == NULL) {
137 dlh = BODY = dlopen(NULL, RTLD_LAZY);
138 if (dlh == NULL)
139 return NULL;
140 }
141 }
142
Jiri Pirkofbea6112014-01-23 17:52:53 +0100143 if (slave)
144 snprintf(buf, sizeof(buf), "%s_slave_link_util", id);
145 else
146 snprintf(buf, sizeof(buf), "%s_link_util", id);
Patrick McHardy1d934832007-08-22 10:49:01 -0700147 l = dlsym(dlh, buf);
148 if (l == NULL)
149 return NULL;
150
151 l->next = linkutil_list;
152 linkutil_list = l;
153 return l;
154}
155
Jiri Pirkofbea6112014-01-23 17:52:53 +0100156struct link_util *get_link_kind(const char *id)
157{
158 return __get_link_kind(id, false);
159}
160
161struct link_util *get_link_slave_kind(const char *id)
162{
163 return __get_link_kind(id, true);
164}
165
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800166static int get_link_mode(const char *mode)
Stephen Hemminger82499282012-03-19 17:24:43 -0700167{
Stephen Hemminger4ccfb442012-04-05 15:10:19 -0700168 if (strcasecmp(mode, "default") == 0)
Stephen Hemminger82499282012-03-19 17:24:43 -0700169 return IF_LINK_MODE_DEFAULT;
Stephen Hemminger4ccfb442012-04-05 15:10:19 -0700170 if (strcasecmp(mode, "dormant") == 0)
Stephen Hemminger82499282012-03-19 17:24:43 -0700171 return IF_LINK_MODE_DORMANT;
172 return -1;
173}
174
Jiri Pirkoff7c2082014-07-11 21:11:46 +0200175static int get_addr_gen_mode(const char *mode)
176{
177 if (strcasecmp(mode, "eui64") == 0)
178 return IN6_ADDR_GEN_MODE_EUI64;
179 if (strcasecmp(mode, "none") == 0)
180 return IN6_ADDR_GEN_MODE_NONE;
Bjørn Mork8e098dd2016-01-04 10:58:04 +0100181 if (strcasecmp(mode, "stable_secret") == 0)
182 return IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
Bjørn Mork8e12bc02016-01-04 10:58:05 +0100183 if (strcasecmp(mode, "random") == 0)
184 return IN6_ADDR_GEN_MODE_RANDOM;
Jiri Pirkoff7c2082014-07-11 21:11:46 +0200185 return -1;
186}
187
Patrick McHardy1d934832007-08-22 10:49:01 -0700188#if IPLINK_IOCTL_COMPAT
189static int have_rtnl_newlink = -1;
190
191static int accept_msg(const struct sockaddr_nl *who,
Nicolas Dichtel0628cdd2015-05-20 16:19:58 +0200192 struct rtnl_ctrl_data *ctrl,
Patrick McHardy1d934832007-08-22 10:49:01 -0700193 struct nlmsghdr *n, void *arg)
194{
195 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
196
Patrick McHardy66e529f2007-10-25 19:46:29 +0200197 if (n->nlmsg_type == NLMSG_ERROR &&
198 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
Patrick McHardy1d934832007-08-22 10:49:01 -0700199 have_rtnl_newlink = 0;
200 else
201 have_rtnl_newlink = 1;
202 return -1;
203}
204
205static int iplink_have_newlink(void)
206{
207 struct {
208 struct nlmsghdr n;
209 struct ifinfomsg i;
210 char buf[1024];
211 } req;
212
213 if (have_rtnl_newlink < 0) {
214 memset(&req, 0, sizeof(req));
215
216 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
217 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
218 req.n.nlmsg_type = RTM_NEWLINK;
219 req.i.ifi_family = AF_UNSPEC;
220
Stephen Hemmingerd2468da2013-12-20 08:15:02 -0800221 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
222 perror("request send failed");
223 exit(1);
224 }
Patrick McHardy1d934832007-08-22 10:49:01 -0700225 rtnl_listen(&rth, accept_msg, NULL);
226 }
227 return have_rtnl_newlink;
228}
229#else /* IPLINK_IOCTL_COMPAT */
230static int iplink_have_newlink(void)
231{
232 return 1;
233}
234#endif /* ! IPLINK_IOCTL_COMPAT */
235
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400236struct iplink_req {
237 struct nlmsghdr n;
238 struct ifinfomsg i;
239 char buf[1024];
240};
241
Phil Sutter8fe58d52016-06-16 16:19:40 +0200242static int nl_get_ll_addr_len(unsigned int dev_index)
243{
244 int len;
245 struct iplink_req req = {
246 .n = {
247 .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
248 .nlmsg_type = RTM_GETLINK,
249 .nlmsg_flags = NLM_F_REQUEST
250 },
251 .i = {
252 .ifi_family = preferred_family,
253 .ifi_index = dev_index,
254 }
255 };
256 struct rtattr *tb[IFLA_MAX+1];
257
258 if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0)
259 return -1;
260
261 len = req.n.nlmsg_len - NLMSG_LENGTH(sizeof(req.i));
262 if (len < 0)
263 return -1;
264
265 parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(&req.i), len, NLA_F_NESTED);
266 if (!tb[IFLA_ADDRESS])
267 return -1;
268
269 return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
270}
271
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800272static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400273 struct iplink_req *req, int dev_index)
Roopa Prabhu632110a2010-11-09 14:47:52 +0000274{
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400275 char new_rate_api = 0, count = 0, override_legacy_rate = 0;
276 struct ifla_vf_rate tivt;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000277 int len, argc = *argcp;
278 char **argv = *argvp;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000279 struct rtattr *vfinfo;
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800280
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400281 tivt.min_tx_rate = -1;
282 tivt.max_tx_rate = -1;
283
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800284 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
Roopa Prabhu632110a2010-11-09 14:47:52 +0000285
286 while (NEXT_ARG_OK()) {
287 NEXT_ARG();
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400288 count++;
289 if (!matches(*argv, "max_tx_rate")) {
290 /* new API in use */
291 new_rate_api = 1;
292 /* override legacy rate */
293 override_legacy_rate = 1;
294 } else if (!matches(*argv, "min_tx_rate")) {
295 /* new API in use */
296 new_rate_api = 1;
297 }
298 }
299
300 while (count--) {
301 /* rewind arg */
302 PREV_ARG();
303 }
304
305 while (NEXT_ARG_OK()) {
306 NEXT_ARG();
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800307 if (matches(*argv, "mac") == 0) {
Phil Suttera89193a2016-06-16 16:19:39 +0200308 struct ifla_vf_mac ivm = { 0 };
Phil Sutter8fe58d52016-06-16 16:19:40 +0200309 int halen = nl_get_ll_addr_len(dev_index);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700310
Roopa Prabhu632110a2010-11-09 14:47:52 +0000311 NEXT_ARG();
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800312 ivm.vf = vf;
313 len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
314 if (len < 0)
315 return -1;
Phil Sutter8fe58d52016-06-16 16:19:40 +0200316 if (halen > 0 && len != halen) {
317 fprintf(stderr,
318 "Invalid address length %d - must be %d bytes\n",
319 len, halen);
320 return -1;
321 }
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700322 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
323 &ivm, sizeof(ivm));
Roopa Prabhu632110a2010-11-09 14:47:52 +0000324 } else if (matches(*argv, "vlan") == 0) {
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800325 struct ifla_vf_vlan ivv;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700326
Roopa Prabhu632110a2010-11-09 14:47:52 +0000327 NEXT_ARG();
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700328 if (get_unsigned(&ivv.vlan, *argv, 0))
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800329 invarg("Invalid \"vlan\" value\n", *argv);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700330
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800331 ivv.vf = vf;
332 ivv.qos = 0;
Roopa Prabhu632110a2010-11-09 14:47:52 +0000333 if (NEXT_ARG_OK()) {
334 NEXT_ARG();
335 if (matches(*argv, "qos") == 0) {
336 NEXT_ARG();
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700337 if (get_unsigned(&ivv.qos, *argv, 0))
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800338 invarg("Invalid \"qos\" value\n", *argv);
Roopa Prabhu632110a2010-11-09 14:47:52 +0000339 } else {
340 /* rewind arg */
341 PREV_ARG();
342 }
343 }
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700344 addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN,
345 &ivv, sizeof(ivv));
Roopa Prabhu632110a2010-11-09 14:47:52 +0000346 } else if (matches(*argv, "rate") == 0) {
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800347 struct ifla_vf_tx_rate ivt;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700348
Roopa Prabhu632110a2010-11-09 14:47:52 +0000349 NEXT_ARG();
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700350 if (get_unsigned(&ivt.rate, *argv, 0))
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800351 invarg("Invalid \"rate\" value\n", *argv);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700352
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800353 ivt.vf = vf;
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400354 if (!new_rate_api)
355 addattr_l(&req->n, sizeof(*req),
356 IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
357 else if (!override_legacy_rate)
358 tivt.max_tx_rate = ivt.rate;
359
360 } else if (matches(*argv, "max_tx_rate") == 0) {
361 NEXT_ARG();
362 if (get_unsigned(&tivt.max_tx_rate, *argv, 0))
363 invarg("Invalid \"max tx rate\" value\n",
364 *argv);
365 tivt.vf = vf;
366
367 } else if (matches(*argv, "min_tx_rate") == 0) {
368 NEXT_ARG();
369 if (get_unsigned(&tivt.min_tx_rate, *argv, 0))
370 invarg("Invalid \"min tx rate\" value\n",
371 *argv);
372 tivt.vf = vf;
xeb@mail.ruaf895762013-09-28 11:32:51 +0400373
Greg Rose7b8179c2011-10-13 20:31:32 +0000374 } else if (matches(*argv, "spoofchk") == 0) {
375 struct ifla_vf_spoofchk ivs;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700376
Greg Rose7b8179c2011-10-13 20:31:32 +0000377 NEXT_ARG();
378 if (matches(*argv, "on") == 0)
379 ivs.setting = 1;
380 else if (matches(*argv, "off") == 0)
381 ivs.setting = 0;
382 else
Zhang Shengjuff1e35e2015-08-13 06:41:50 +0000383 return on_off("spoofchk", *argv);
Greg Rose7b8179c2011-10-13 20:31:32 +0000384 ivs.vf = vf;
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700385 addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK,
386 &ivs, sizeof(ivs));
Greg Rose7b8179c2011-10-13 20:31:32 +0000387
Vlad Zolotarov6c55c8c2015-04-30 13:46:43 +0300388 } else if (matches(*argv, "query_rss") == 0) {
389 struct ifla_vf_rss_query_en ivs;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700390
Vlad Zolotarov6c55c8c2015-04-30 13:46:43 +0300391 NEXT_ARG();
392 if (matches(*argv, "on") == 0)
393 ivs.setting = 1;
394 else if (matches(*argv, "off") == 0)
395 ivs.setting = 0;
396 else
Zhang Shengjuff1e35e2015-08-13 06:41:50 +0000397 return on_off("query_rss", *argv);
Vlad Zolotarov6c55c8c2015-04-30 13:46:43 +0300398 ivs.vf = vf;
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700399 addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN,
400 &ivs, sizeof(ivs));
Vlad Zolotarov6c55c8c2015-04-30 13:46:43 +0300401
Hiroshi Shimamotob6d77d92016-02-26 02:40:18 +0000402 } else if (matches(*argv, "trust") == 0) {
403 struct ifla_vf_trust ivt;
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700404
Hiroshi Shimamotob6d77d92016-02-26 02:40:18 +0000405 NEXT_ARG();
406 if (matches(*argv, "on") == 0)
407 ivt.setting = 1;
408 else if (matches(*argv, "off") == 0)
409 ivt.setting = 0;
410 else
411 invarg("Invalid \"trust\" value\n", *argv);
412 ivt.vf = vf;
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700413 addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST,
414 &ivt, sizeof(ivt));
Hiroshi Shimamotob6d77d92016-02-26 02:40:18 +0000415
Rony Efraim07fa9c12013-06-13 13:19:12 +0300416 } else if (matches(*argv, "state") == 0) {
417 struct ifla_vf_link_state ivl;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700418
Rony Efraim07fa9c12013-06-13 13:19:12 +0300419 NEXT_ARG();
420 if (matches(*argv, "auto") == 0)
421 ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
422 else if (matches(*argv, "enable") == 0)
423 ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
424 else if (matches(*argv, "disable") == 0)
425 ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
426 else
427 invarg("Invalid \"state\" value\n", *argv);
428 ivl.vf = vf;
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700429 addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE,
430 &ivl, sizeof(ivl));
Eli Cohend91fb3f2016-07-07 16:09:03 -0500431 } else if (matches(*argv, "node_guid") == 0) {
432 struct ifla_vf_guid ivg;
433
434 NEXT_ARG();
435 ivg.vf = vf;
436 if (get_guid(&ivg.guid, *argv)) {
437 invarg("Invalid GUID format\n", *argv);
438 return -1;
439 }
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700440 addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_NODE_GUID,
441 &ivg, sizeof(ivg));
Eli Cohend91fb3f2016-07-07 16:09:03 -0500442 } else if (matches(*argv, "port_guid") == 0) {
443 struct ifla_vf_guid ivg;
444
445 NEXT_ARG();
446 ivg.vf = vf;
447 if (get_guid(&ivg.guid, *argv)) {
448 invarg("Invalid GUID format\n", *argv);
449 return -1;
450 }
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700451 addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_PORT_GUID,
452 &ivg, sizeof(ivg));
Roopa Prabhu632110a2010-11-09 14:47:52 +0000453 } else {
454 /* rewind arg */
455 PREV_ARG();
456 break;
457 }
458 }
459
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400460 if (new_rate_api) {
461 int tmin, tmax;
Stephen Hemminger9a026512014-07-14 12:08:05 -0700462
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400463 if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
464 ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
465 if (tivt.min_tx_rate == -1)
466 tivt.min_tx_rate = tmin;
467 if (tivt.max_tx_rate == -1)
468 tivt.max_tx_rate = tmax;
469 }
470 addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
471 sizeof(tivt));
472 }
473
Roopa Prabhu632110a2010-11-09 14:47:52 +0000474 if (argc == *argcp)
475 incomplete_command();
476
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800477 addattr_nest_end(&req->n, vfinfo);
Roopa Prabhu632110a2010-11-09 14:47:52 +0000478
479 *argcp = argc;
480 *argvp = argv;
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800481 return 0;
Chris Wright3fd86632010-05-18 00:57:00 -0700482}
483
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400484int iplink_parse(int argc, char **argv, struct iplink_req *req,
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700485 char **name, char **type, char **link, char **dev,
486 int *group, int *index)
Patrick McHardy1d934832007-08-22 10:49:01 -0700487{
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400488 int ret, len;
489 char abuf[32];
Patrick McHardy1d934832007-08-22 10:49:01 -0700490 int qlen = -1;
491 int mtu = -1;
Benjamin Therye2613dc2008-06-20 11:07:35 +0200492 int netns = -1;
Williams, Mitch Aae7229d2010-02-10 01:47:08 +0000493 int vf = -1;
Jiri Pirkod992f3e2012-08-01 16:19:55 -0700494 int numtxqueues = -1;
495 int numrxqueues = -1;
Stephen Hemminger9a026512014-07-14 12:08:05 -0700496 int dev_index = 0;
Nicolas Dichtelccdcbf32015-02-17 17:30:38 +0100497 int link_netnsid = -1;
Phil Sutter8fe58d52016-06-16 16:19:40 +0200498 int addr_len = 0;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400499
Vlad Dogarudb026082011-02-02 20:23:41 +0200500 *group = -1;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400501 ret = argc;
502
503 while (argc > 0) {
504 if (strcmp(*argv, "up") == 0) {
505 req->i.ifi_change |= IFF_UP;
506 req->i.ifi_flags |= IFF_UP;
507 } else if (strcmp(*argv, "down") == 0) {
508 req->i.ifi_change |= IFF_UP;
509 req->i.ifi_flags &= ~IFF_UP;
510 } else if (strcmp(*argv, "name") == 0) {
511 NEXT_ARG();
512 *name = *argv;
Pavel Emelyanov5e25cf72013-12-26 23:15:20 +0400513 } else if (strcmp(*argv, "index") == 0) {
514 NEXT_ARG();
515 *index = atoi(*argv);
WANG Cong3c682142014-09-05 16:36:14 -0700516 if (*index < 0)
517 invarg("Invalid \"index\" value", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400518 } else if (matches(*argv, "link") == 0) {
519 NEXT_ARG();
520 *link = *argv;
521 } else if (matches(*argv, "address") == 0) {
522 NEXT_ARG();
Phil Sutter8fe58d52016-06-16 16:19:40 +0200523 addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
Phil Sutter0aae2342016-06-22 12:05:38 +0200524 if (addr_len < 0)
Andreas Henrikssoncb2eb992009-04-30 16:50:50 +0200525 return -1;
Phil Sutter8fe58d52016-06-16 16:19:40 +0200526 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, addr_len);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400527 } else if (matches(*argv, "broadcast") == 0 ||
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700528 strcmp(*argv, "brd") == 0) {
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400529 NEXT_ARG();
530 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
Andreas Henrikssoncb2eb992009-04-30 16:50:50 +0200531 if (len < 0)
532 return -1;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400533 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
534 } else if (matches(*argv, "txqueuelen") == 0 ||
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700535 strcmp(*argv, "qlen") == 0 ||
536 matches(*argv, "txqlen") == 0) {
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400537 NEXT_ARG();
538 if (qlen != -1)
539 duparg("txqueuelen", *argv);
540 if (get_integer(&qlen, *argv, 0))
541 invarg("Invalid \"txqueuelen\" value\n", *argv);
542 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
543 } else if (strcmp(*argv, "mtu") == 0) {
544 NEXT_ARG();
545 if (mtu != -1)
546 duparg("mtu", *argv);
547 if (get_integer(&mtu, *argv, 0))
548 invarg("Invalid \"mtu\" value\n", *argv);
549 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
Stephen Hemminger4b726cb2014-05-09 12:36:46 -0700550 } else if (strcmp(*argv, "netns") == 0) {
551 NEXT_ARG();
552 if (netns != -1)
553 duparg("netns", *argv);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700554 netns = netns_get_fd(*argv);
555 if (netns >= 0)
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700556 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
557 &netns, 4);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700558 else if (get_integer(&netns, *argv, 0) == 0)
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700559 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID,
560 &netns, 4);
Eric W. Biederman0dc34c72011-07-13 09:48:26 -0700561 else
Stephen Hemminger4b726cb2014-05-09 12:36:46 -0700562 invarg("Invalid \"netns\" value\n", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400563 } else if (strcmp(*argv, "multicast") == 0) {
564 NEXT_ARG();
565 req->i.ifi_change |= IFF_MULTICAST;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700566
567 if (strcmp(*argv, "on") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400568 req->i.ifi_flags |= IFF_MULTICAST;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700569 else if (strcmp(*argv, "off") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400570 req->i.ifi_flags &= ~IFF_MULTICAST;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700571 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000572 return on_off("multicast", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400573 } else if (strcmp(*argv, "allmulticast") == 0) {
574 NEXT_ARG();
575 req->i.ifi_change |= IFF_ALLMULTI;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700576
577 if (strcmp(*argv, "on") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400578 req->i.ifi_flags |= IFF_ALLMULTI;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700579 else if (strcmp(*argv, "off") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400580 req->i.ifi_flags &= ~IFF_ALLMULTI;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700581 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000582 return on_off("allmulticast", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400583 } else if (strcmp(*argv, "promisc") == 0) {
584 NEXT_ARG();
585 req->i.ifi_change |= IFF_PROMISC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700586
587 if (strcmp(*argv, "on") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400588 req->i.ifi_flags |= IFF_PROMISC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700589 else if (strcmp(*argv, "off") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400590 req->i.ifi_flags &= ~IFF_PROMISC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700591 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000592 return on_off("promisc", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400593 } else if (strcmp(*argv, "trailers") == 0) {
594 NEXT_ARG();
595 req->i.ifi_change |= IFF_NOTRAILERS;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700596
597 if (strcmp(*argv, "off") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400598 req->i.ifi_flags |= IFF_NOTRAILERS;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700599 else if (strcmp(*argv, "on") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400600 req->i.ifi_flags &= ~IFF_NOTRAILERS;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700601 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000602 return on_off("trailers", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400603 } else if (strcmp(*argv, "arp") == 0) {
604 NEXT_ARG();
605 req->i.ifi_change |= IFF_NOARP;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700606
607 if (strcmp(*argv, "on") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400608 req->i.ifi_flags &= ~IFF_NOARP;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700609 else if (strcmp(*argv, "off") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400610 req->i.ifi_flags |= IFF_NOARP;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700611 else
Zhang Shengjue543a6a2015-08-12 06:29:59 +0000612 return on_off("arp", *argv);
Williams, Mitch Aae7229d2010-02-10 01:47:08 +0000613 } else if (strcmp(*argv, "vf") == 0) {
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800614 struct rtattr *vflist;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700615
Williams, Mitch Aae7229d2010-02-10 01:47:08 +0000616 NEXT_ARG();
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700617 if (get_integer(&vf, *argv, 0))
Williams, Mitch Aae7229d2010-02-10 01:47:08 +0000618 invarg("Invalid \"vf\" value\n", *argv);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700619
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800620 vflist = addattr_nest(&req->n, sizeof(*req),
621 IFLA_VFINFO_LIST);
Stephen Hemminger9a026512014-07-14 12:08:05 -0700622 if (dev_index == 0)
623 missarg("dev");
624
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400625 len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
Stephen Hemminger1598b9e2011-01-13 14:53:02 -0800626 if (len < 0)
627 return -1;
628 addattr_nest_end(&req->n, vflist);
Jiri Pirkoa1e191b2011-02-25 19:55:19 -0800629 } else if (matches(*argv, "master") == 0) {
630 int ifindex;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700631
Jiri Pirkoa1e191b2011-02-25 19:55:19 -0800632 NEXT_ARG();
633 ifindex = ll_name_to_index(*argv);
634 if (!ifindex)
635 invarg("Device does not exist\n", *argv);
636 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
637 &ifindex, 4);
David Ahern104444c2016-06-29 11:26:58 -0700638 } else if (strcmp(*argv, "vrf") == 0) {
639 int ifindex;
640
641 NEXT_ARG();
642 ifindex = ll_name_to_index(*argv);
643 if (!ifindex)
644 invarg("Not a valid VRF name\n", *argv);
645 if (!name_is_vrf(*argv))
646 invarg("Not a valid VRF name\n", *argv);
647 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
648 &ifindex, sizeof(ifindex));
Jiri Pirkoa1e191b2011-02-25 19:55:19 -0800649 } else if (matches(*argv, "nomaster") == 0) {
650 int ifindex = 0;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700651
Jiri Pirkoa1e191b2011-02-25 19:55:19 -0800652 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
653 &ifindex, 4);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400654 } else if (matches(*argv, "dynamic") == 0) {
655 NEXT_ARG();
656 req->i.ifi_change |= IFF_DYNAMIC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700657
658 if (strcmp(*argv, "on") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400659 req->i.ifi_flags |= IFF_DYNAMIC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700660 else if (strcmp(*argv, "off") == 0)
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400661 req->i.ifi_flags &= ~IFF_DYNAMIC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700662 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +0000663 return on_off("dynamic", *argv);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400664 } else if (matches(*argv, "type") == 0) {
665 NEXT_ARG();
666 *type = *argv;
667 argc--; argv++;
668 break;
Stephen Hemmingerace9c962009-03-23 10:46:47 -0700669 } else if (matches(*argv, "alias") == 0) {
670 NEXT_ARG();
671 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
672 *argv, strlen(*argv));
673 argc--; argv++;
674 break;
Vlad Dogarudb026082011-02-02 20:23:41 +0200675 } else if (strcmp(*argv, "group") == 0) {
676 NEXT_ARG();
677 if (*group != -1)
678 duparg("group", *argv);
679 if (rtnl_group_a2n(group, *argv))
680 invarg("Invalid \"group\" value\n", *argv);
Stephen Hemminger82499282012-03-19 17:24:43 -0700681 } else if (strcmp(*argv, "mode") == 0) {
682 int mode;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700683
Stephen Hemminger82499282012-03-19 17:24:43 -0700684 NEXT_ARG();
Stephen Hemminger4ccfb442012-04-05 15:10:19 -0700685 mode = get_link_mode(*argv);
Stephen Hemminger82499282012-03-19 17:24:43 -0700686 if (mode < 0)
687 invarg("Invalid link mode\n", *argv);
688 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
Stephen Hemminger4f2fdd42012-04-05 15:08:57 -0700689 } else if (strcmp(*argv, "state") == 0) {
690 int state;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700691
Stephen Hemminger4f2fdd42012-04-05 15:08:57 -0700692 NEXT_ARG();
693 state = get_operstate(*argv);
694 if (state < 0)
695 invarg("Invalid operstate\n", *argv);
696
697 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
Jiri Pirkod992f3e2012-08-01 16:19:55 -0700698 } else if (matches(*argv, "numtxqueues") == 0) {
699 NEXT_ARG();
700 if (numtxqueues != -1)
701 duparg("numtxqueues", *argv);
702 if (get_integer(&numtxqueues, *argv, 0))
703 invarg("Invalid \"numtxqueues\" value\n", *argv);
704 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
705 &numtxqueues, 4);
706 } else if (matches(*argv, "numrxqueues") == 0) {
707 NEXT_ARG();
708 if (numrxqueues != -1)
709 duparg("numrxqueues", *argv);
710 if (get_integer(&numrxqueues, *argv, 0))
711 invarg("Invalid \"numrxqueues\" value\n", *argv);
712 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
713 &numrxqueues, 4);
Jiri Pirkoff7c2082014-07-11 21:11:46 +0200714 } else if (matches(*argv, "addrgenmode") == 0) {
715 struct rtattr *afs, *afs6;
716 int mode;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -0700717
Jiri Pirkoff7c2082014-07-11 21:11:46 +0200718 NEXT_ARG();
719 mode = get_addr_gen_mode(*argv);
720 if (mode < 0)
721 invarg("Invalid address generation mode\n", *argv);
722 afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
723 afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700724 addattr8(&req->n, sizeof(*req),
725 IFLA_INET6_ADDR_GEN_MODE, mode);
Jiri Pirkoff7c2082014-07-11 21:11:46 +0200726 addattr_nest_end(&req->n, afs6);
727 addattr_nest_end(&req->n, afs);
Nicolas Dichtelccdcbf32015-02-17 17:30:38 +0100728 } else if (matches(*argv, "link-netnsid") == 0) {
729 NEXT_ARG();
730 if (link_netnsid != -1)
731 duparg("link-netnsid", *argv);
732 if (get_integer(&link_netnsid, *argv, 0))
733 invarg("Invalid \"link-netnsid\" value\n", *argv);
734 addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
735 link_netnsid);
Anuradha Karuppiah18864822015-07-14 13:43:22 -0700736 } else if (strcmp(*argv, "protodown") == 0) {
737 unsigned int proto_down;
738
739 NEXT_ARG();
740 if (strcmp(*argv, "on") == 0)
741 proto_down = 1;
742 else if (strcmp(*argv, "off") == 0)
743 proto_down = 0;
744 else
745 return on_off("protodown", *argv);
746 addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
747 proto_down);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400748 } else {
Patrick McHardy05325552008-10-07 17:16:08 +0200749 if (matches(*argv, "help") == 0)
750 usage();
Phil Sutter940a96e2015-09-21 21:33:01 +0200751
752 if (strcmp(*argv, "dev") == 0)
753 NEXT_ARG();
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400754 if (*dev)
755 duparg2("dev", *argv);
756 *dev = *argv;
Sucheta Chakrabortyf89a2a02014-05-22 09:59:37 -0400757 dev_index = ll_name_to_index(*dev);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400758 }
759 argc--; argv++;
760 }
761
Phil Sutter8fe58d52016-06-16 16:19:40 +0200762 if (dev_index && addr_len) {
763 int halen = nl_get_ll_addr_len(dev_index);
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700764
Phil Sutter8fe58d52016-06-16 16:19:40 +0200765 if (halen >= 0 && halen != addr_len) {
766 fprintf(stderr,
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700767 "Invalid address length %d - must be %d bytes\n",
768 addr_len, halen);
Phil Sutter8fe58d52016-06-16 16:19:40 +0200769 return -1;
770 }
771 }
772
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400773 return ret - argc;
774}
775
776static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
777{
Patrick McHardy1d934832007-08-22 10:49:01 -0700778 int len;
Patrick McHardy1d934832007-08-22 10:49:01 -0700779 char *dev = NULL;
780 char *name = NULL;
781 char *link = NULL;
782 char *type = NULL;
WANG Cong3c682142014-09-05 16:36:14 -0700783 int index = -1;
Vlad Dogarudb026082011-02-02 20:23:41 +0200784 int group;
Patrick McHardy1d934832007-08-22 10:49:01 -0700785 struct link_util *lu = NULL;
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400786 struct iplink_req req;
787 int ret;
Patrick McHardy1d934832007-08-22 10:49:01 -0700788
789 memset(&req, 0, sizeof(req));
790
791 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
792 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
793 req.n.nlmsg_type = cmd;
794 req.i.ifi_family = preferred_family;
795
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700796 ret = iplink_parse(argc, argv,
797 &req, &name, &type, &link, &dev, &group, &index);
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400798 if (ret < 0)
799 return ret;
Patrick McHardy1d934832007-08-22 10:49:01 -0700800
Pavel Emelyanov909dfe22007-07-19 13:32:31 +0400801 argc -= ret;
802 argv += ret;
Vlad Dogarudb026082011-02-02 20:23:41 +0200803
804 if (group != -1) {
805 if (dev)
806 addattr_l(&req.n, sizeof(req), IFLA_GROUP,
807 &group, sizeof(group));
808 else {
809 if (argc) {
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700810 fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
811 *argv);
Vlad Dogarudb026082011-02-02 20:23:41 +0200812 return -1;
813 }
814 if (flags & NLM_F_CREATE) {
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700815 fprintf(stderr, "group cannot be used when creating devices.\n");
Vlad Dogarudb026082011-02-02 20:23:41 +0200816 return -1;
817 }
818
819 req.i.ifi_index = 0;
820 addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700821 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
Roopa Prabhuf921f562016-01-09 16:02:12 -0800822 return -2;
Vlad Dogarudb026082011-02-02 20:23:41 +0200823 return 0;
824 }
825 }
826
Patrick McHardy1d934832007-08-22 10:49:01 -0700827 if (!(flags & NLM_F_CREATE)) {
828 if (!dev) {
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700829 fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
Patrick McHardy1d934832007-08-22 10:49:01 -0700830 exit(-1);
831 }
WANG Cong3c682142014-09-05 16:36:14 -0700832 if (cmd == RTM_NEWLINK && index != -1) {
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700833 fprintf(stderr, "index can be used only when creating devices.\n");
WANG Cong3c682142014-09-05 16:36:14 -0700834 exit(-1);
835 }
Patrick McHardy1d934832007-08-22 10:49:01 -0700836
837 req.i.ifi_index = ll_name_to_index(dev);
838 if (req.i.ifi_index == 0) {
839 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
840 return -1;
841 }
842 } else {
843 /* Allow "ip link add dev" and "ip link add name" */
844 if (!name)
845 name = dev;
846
847 if (link) {
848 int ifindex;
849
850 ifindex = ll_name_to_index(link);
851 if (ifindex == 0) {
852 fprintf(stderr, "Cannot find device \"%s\"\n",
853 link);
854 return -1;
855 }
856 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
857 }
Pavel Emelyanov5e25cf72013-12-26 23:15:20 +0400858
Atzm Watanabe68ac9ab2014-10-01 14:47:50 +0900859 if (index == -1)
860 req.i.ifi_index = 0;
861 else
862 req.i.ifi_index = index;
Patrick McHardy1d934832007-08-22 10:49:01 -0700863 }
864
865 if (name) {
866 len = strlen(name) + 1;
Patrick McHardyca78b0e2007-10-12 14:01:13 +0200867 if (len == 1)
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700868 invarg("\"\" is not a valid device identifier\n",
869 "name");
Patrick McHardy1d934832007-08-22 10:49:01 -0700870 if (len > IFNAMSIZ)
Patrick McHardyca78b0e2007-10-12 14:01:13 +0200871 invarg("\"name\" too long\n", name);
Patrick McHardy1d934832007-08-22 10:49:01 -0700872 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
873 }
874
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700875 if (type) {
Duan Jionga1e2e5f2014-12-17 15:28:45 +0800876 struct rtattr *linkinfo;
Nikolay Aleksandrov620dded2014-09-03 17:57:30 +0200877 char slavebuf[128], *ulinep = strchr(type, '_');
878 int iflatype;
879
Duan Jionga1e2e5f2014-12-17 15:28:45 +0800880 linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700881 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
882 strlen(type));
883
Nikolay Aleksandrov620dded2014-09-03 17:57:30 +0200884 if (ulinep && !strcmp(ulinep, "_slave")) {
885 strncpy(slavebuf, type, sizeof(slavebuf));
886 slavebuf[sizeof(slavebuf) - 1] = '\0';
887 ulinep = strchr(slavebuf, '_');
888 /* check in case it was after sizeof(slavebuf) - 1*/
889 if (ulinep)
890 *ulinep = '\0';
891 lu = get_link_slave_kind(slavebuf);
892 iflatype = IFLA_INFO_SLAVE_DATA;
893 } else {
894 lu = get_link_kind(type);
895 iflatype = IFLA_INFO_DATA;
896 }
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700897 if (lu && argc) {
Stephen Hemmingeref0a7382016-07-15 11:31:20 -0700898 struct rtattr *data = addattr_nest(&req.n,
899 sizeof(req), iflatype);
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700900
901 if (lu->parse_opt &&
902 lu->parse_opt(lu, argc, argv, &req.n))
903 return -1;
904
Duan Jionga1e2e5f2014-12-17 15:28:45 +0800905 addattr_nest_end(&req.n, data);
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700906 } else if (argc) {
907 if (matches(*argv, "help") == 0)
908 usage();
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700909 fprintf(stderr, "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
910 *argv);
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700911 return -1;
912 }
Duan Jionga1e2e5f2014-12-17 15:28:45 +0800913 addattr_nest_end(&req.n, linkinfo);
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700914 } else if (flags & NLM_F_CREATE) {
Stephen Hemminger56f5daa2016-03-21 11:52:19 -0700915 fprintf(stderr, "Not enough information: \"type\" argument is required\n");
Stephen Hemminger09fa3272012-03-14 10:24:25 -0700916 return -1;
917 }
918
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700919 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
Roopa Prabhuf921f562016-01-09 16:02:12 -0800920 return -2;
Patrick McHardy1d934832007-08-22 10:49:01 -0700921
922 return 0;
923}
924
Roopa Prabhu50b99502014-07-16 07:13:25 -0700925int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
926{
927 int len;
928 struct iplink_req req;
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700929 struct {
930 struct nlmsghdr n;
931 char buf[16384];
932 } answer;
Roopa Prabhu50b99502014-07-16 07:13:25 -0700933
934 memset(&req, 0, sizeof(req));
935
936 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
937 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
938 req.n.nlmsg_type = RTM_GETLINK;
939 req.i.ifi_family = preferred_family;
940
941 if (name) {
942 len = strlen(name) + 1;
943 if (len == 1)
944 invarg("\"\" is not a valid device identifier\n",
945 "name");
946 if (len > IFNAMSIZ)
947 invarg("\"name\" too long\n", name);
948 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
949 }
950 addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
951
Stephen Hemmingerc079e122015-05-27 12:26:14 -0700952 if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
Roopa Prabhu50b99502014-07-16 07:13:25 -0700953 return -2;
954
Andy Gospodarek5d295bb2015-08-28 13:45:41 -0400955 if (brief)
956 print_linkinfo_brief(NULL, &answer.n, stdout);
957 else
958 print_linkinfo(NULL, &answer.n, stdout);
Roopa Prabhu50b99502014-07-16 07:13:25 -0700959
960 return 0;
961}
962
Patrick McHardy1d934832007-08-22 10:49:01 -0700963#if IPLINK_IOCTL_COMPAT
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000964static int get_ctl_fd(void)
965{
966 int s_errno;
967 int fd;
968
969 fd = socket(PF_INET, SOCK_DGRAM, 0);
970 if (fd >= 0)
971 return fd;
972 s_errno = errno;
973 fd = socket(PF_PACKET, SOCK_DGRAM, 0);
974 if (fd >= 0)
975 return fd;
976 fd = socket(PF_INET6, SOCK_DGRAM, 0);
977 if (fd >= 0)
978 return fd;
979 errno = s_errno;
980 perror("Cannot create control socket");
981 return -1;
982}
983
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000984static int do_chflags(const char *dev, __u32 flags, __u32 mask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000985{
986 struct ifreq ifr;
987 int fd;
988 int err;
989
osdl.net!shemminger71058eb2004-09-01 17:15:45 +0000990 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000991 fd = get_ctl_fd();
992 if (fd < 0)
993 return -1;
994 err = ioctl(fd, SIOCGIFFLAGS, &ifr);
995 if (err) {
996 perror("SIOCGIFFLAGS");
997 close(fd);
998 return -1;
999 }
1000 if ((ifr.ifr_flags^flags)&mask) {
1001 ifr.ifr_flags &= ~mask;
1002 ifr.ifr_flags |= mask&flags;
1003 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
1004 if (err)
1005 perror("SIOCSIFFLAGS");
1006 }
1007 close(fd);
1008 return err;
1009}
1010
osdl.net!shemminger71058eb2004-09-01 17:15:45 +00001011static int do_changename(const char *dev, const char *newdev)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001012{
1013 struct ifreq ifr;
1014 int fd;
1015 int err;
1016
osdl.net!shemminger71058eb2004-09-01 17:15:45 +00001017 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
1018 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001019 fd = get_ctl_fd();
1020 if (fd < 0)
1021 return -1;
1022 err = ioctl(fd, SIOCSIFNAME, &ifr);
1023 if (err) {
1024 perror("SIOCSIFNAME");
1025 close(fd);
1026 return -1;
1027 }
1028 close(fd);
1029 return err;
1030}
1031
osdl.net!shemminger71058eb2004-09-01 17:15:45 +00001032static int set_qlen(const char *dev, int qlen)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001033{
1034 struct ifreq ifr;
1035 int s;
1036
1037 s = get_ctl_fd();
1038 if (s < 0)
1039 return -1;
1040
1041 memset(&ifr, 0, sizeof(ifr));
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001042 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
1043 ifr.ifr_qlen = qlen;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001044 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
1045 perror("SIOCSIFXQLEN");
1046 close(s);
1047 return -1;
1048 }
1049 close(s);
1050
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001051 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001052}
1053
osdl.net!shemminger71058eb2004-09-01 17:15:45 +00001054static int set_mtu(const char *dev, int mtu)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001055{
1056 struct ifreq ifr;
1057 int s;
1058
1059 s = get_ctl_fd();
1060 if (s < 0)
1061 return -1;
1062
1063 memset(&ifr, 0, sizeof(ifr));
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001064 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
1065 ifr.ifr_mtu = mtu;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001066 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
1067 perror("SIOCSIFMTU");
1068 close(s);
1069 return -1;
1070 }
1071 close(s);
1072
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001073 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001074}
1075
osdl.net!shemminger71058eb2004-09-01 17:15:45 +00001076static int get_address(const char *dev, int *htype)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001077{
1078 struct ifreq ifr;
1079 struct sockaddr_ll me;
shemmingerf332d162005-07-05 22:37:15 +00001080 socklen_t alen;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001081 int s;
1082
1083 s = socket(PF_PACKET, SOCK_DGRAM, 0);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001084 if (s < 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001085 perror("socket(PF_PACKET)");
1086 return -1;
1087 }
1088
1089 memset(&ifr, 0, sizeof(ifr));
osdl.net!shemminger71058eb2004-09-01 17:15:45 +00001090 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001091 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
1092 perror("SIOCGIFINDEX");
1093 close(s);
1094 return -1;
1095 }
1096
1097 memset(&me, 0, sizeof(me));
1098 me.sll_family = AF_PACKET;
1099 me.sll_ifindex = ifr.ifr_ifindex;
1100 me.sll_protocol = htons(ETH_P_LOOP);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001101 if (bind(s, (struct sockaddr *)&me, sizeof(me)) == -1) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001102 perror("bind");
1103 close(s);
1104 return -1;
1105 }
1106
1107 alen = sizeof(me);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001108 if (getsockname(s, (struct sockaddr *)&me, &alen) == -1) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001109 perror("getsockname");
1110 close(s);
1111 return -1;
1112 }
1113 close(s);
1114 *htype = me.sll_hatype;
1115 return me.sll_halen;
1116}
1117
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001118static int parse_address(const char *dev, int hatype, int halen,
shemminger7b565752006-03-21 23:57:50 +00001119 char *lla, struct ifreq *ifr)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001120{
1121 int alen;
1122
1123 memset(ifr, 0, sizeof(*ifr));
osdl.net!shemminger71058eb2004-09-01 17:15:45 +00001124 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001125 ifr->ifr_hwaddr.sa_family = hatype;
1126 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
1127 if (alen < 0)
1128 return -1;
1129 if (alen != halen) {
Stephen Hemmingeref0a7382016-07-15 11:31:20 -07001130 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n",
1131 lla, halen);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001132 return -1;
1133 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001134 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001135}
1136
1137static int set_address(struct ifreq *ifr, int brd)
1138{
1139 int s;
1140
1141 s = get_ctl_fd();
1142 if (s < 0)
1143 return -1;
1144 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
1145 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
1146 close(s);
1147 return -1;
1148 }
1149 close(s);
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001150 return 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001151}
1152
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001153static int do_set(int argc, char **argv)
1154{
1155 char *dev = NULL;
1156 __u32 mask = 0;
1157 __u32 flags = 0;
1158 int qlen = -1;
1159 int mtu = -1;
1160 char *newaddr = NULL;
1161 char *newbrd = NULL;
1162 struct ifreq ifr0, ifr1;
1163 char *newname = NULL;
1164 int htype, halen;
1165
1166 while (argc > 0) {
1167 if (strcmp(*argv, "up") == 0) {
1168 mask |= IFF_UP;
1169 flags |= IFF_UP;
1170 } else if (strcmp(*argv, "down") == 0) {
1171 mask |= IFF_UP;
1172 flags &= ~IFF_UP;
1173 } else if (strcmp(*argv, "name") == 0) {
1174 NEXT_ARG();
1175 newname = *argv;
1176 } else if (matches(*argv, "address") == 0) {
1177 NEXT_ARG();
1178 newaddr = *argv;
1179 } else if (matches(*argv, "broadcast") == 0 ||
1180 strcmp(*argv, "brd") == 0) {
1181 NEXT_ARG();
1182 newbrd = *argv;
1183 } else if (matches(*argv, "txqueuelen") == 0 ||
1184 strcmp(*argv, "qlen") == 0 ||
1185 matches(*argv, "txqlen") == 0) {
1186 NEXT_ARG();
1187 if (qlen != -1)
1188 duparg("txqueuelen", *argv);
1189 if (get_integer(&qlen, *argv, 0))
1190 invarg("Invalid \"txqueuelen\" value\n", *argv);
1191 } else if (strcmp(*argv, "mtu") == 0) {
1192 NEXT_ARG();
1193 if (mtu != -1)
1194 duparg("mtu", *argv);
1195 if (get_integer(&mtu, *argv, 0))
1196 invarg("Invalid \"mtu\" value\n", *argv);
1197 } else if (strcmp(*argv, "multicast") == 0) {
1198 NEXT_ARG();
1199 mask |= IFF_MULTICAST;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001200
1201 if (strcmp(*argv, "on") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001202 flags |= IFF_MULTICAST;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001203 else if (strcmp(*argv, "off") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001204 flags &= ~IFF_MULTICAST;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001205 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +00001206 return on_off("multicast", *argv);
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001207 } else if (strcmp(*argv, "allmulticast") == 0) {
1208 NEXT_ARG();
1209 mask |= IFF_ALLMULTI;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001210
1211 if (strcmp(*argv, "on") == 0)
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001212 flags |= IFF_ALLMULTI;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001213 else if (strcmp(*argv, "off") == 0)
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001214 flags &= ~IFF_ALLMULTI;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001215 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +00001216 return on_off("allmulticast", *argv);
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001217 } else if (strcmp(*argv, "promisc") == 0) {
1218 NEXT_ARG();
1219 mask |= IFF_PROMISC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001220
1221 if (strcmp(*argv, "on") == 0)
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001222 flags |= IFF_PROMISC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001223 else if (strcmp(*argv, "off") == 0)
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001224 flags &= ~IFF_PROMISC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001225 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +00001226 return on_off("promisc", *argv);
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001227 } else if (strcmp(*argv, "trailers") == 0) {
1228 NEXT_ARG();
1229 mask |= IFF_NOTRAILERS;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001230
1231 if (strcmp(*argv, "off") == 0)
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001232 flags |= IFF_NOTRAILERS;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001233 else if (strcmp(*argv, "on") == 0)
net[shemminger]!shemmingerd27b1b52004-07-01 22:15:50 +00001234 flags &= ~IFF_NOTRAILERS;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001235 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +00001236 return on_off("trailers", *argv);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001237 } else if (strcmp(*argv, "arp") == 0) {
1238 NEXT_ARG();
1239 mask |= IFF_NOARP;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001240
1241 if (strcmp(*argv, "on") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001242 flags &= ~IFF_NOARP;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001243 else if (strcmp(*argv, "off") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001244 flags |= IFF_NOARP;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001245 else
Zhang Shengjuff1e35e2015-08-13 06:41:50 +00001246 return on_off("arp", *argv);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001247 } else if (matches(*argv, "dynamic") == 0) {
1248 NEXT_ARG();
1249 mask |= IFF_DYNAMIC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001250
1251 if (strcmp(*argv, "on") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001252 flags |= IFF_DYNAMIC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001253 else if (strcmp(*argv, "off") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001254 flags &= ~IFF_DYNAMIC;
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001255 else
Kees van Reeuwijk14645ec2013-02-08 03:32:36 +00001256 return on_off("dynamic", *argv);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001257 } else {
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001258 if (strcmp(*argv, "dev") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001259 NEXT_ARG();
Christoph Schulz8aacb9b2015-09-25 08:44:07 +02001260 else if (matches(*argv, "help") == 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001261 usage();
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001262
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001263 if (dev)
1264 duparg2("dev", *argv);
1265 dev = *argv;
1266 }
1267 argc--; argv++;
1268 }
1269
1270 if (!dev) {
Stephen Hemmingeref0a7382016-07-15 11:31:20 -07001271 fprintf(stderr,
1272 "Not enough of information: \"dev\" argument is required.\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001273 exit(-1);
1274 }
1275
1276 if (newaddr || newbrd) {
1277 halen = get_address(dev, &htype);
1278 if (halen < 0)
1279 return -1;
1280 if (newaddr) {
1281 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
1282 return -1;
1283 }
1284 if (newbrd) {
1285 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001286 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001287 }
1288 }
1289
1290 if (newname && strcmp(dev, newname)) {
Patrick McHardyca78b0e2007-10-12 14:01:13 +02001291 if (strlen(newname) == 0)
1292 invarg("\"\" is not a valid device identifier\n", "name");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001293 if (do_changename(dev, newname) < 0)
1294 return -1;
1295 dev = newname;
1296 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001297 if (qlen != -1) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001298 if (set_qlen(dev, qlen) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001299 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001300 }
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001301 if (mtu != -1) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001302 if (set_mtu(dev, mtu) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001303 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001304 }
1305 if (newaddr || newbrd) {
1306 if (newbrd) {
1307 if (set_address(&ifr1, 1) < 0)
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001308 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001309 }
1310 if (newaddr) {
1311 if (set_address(&ifr0, 0) < 0)
1312 return -1;
1313 }
1314 }
1315 if (mask)
1316 return do_chflags(dev, flags, mask);
1317 return 0;
1318}
Patrick McHardy1d934832007-08-22 10:49:01 -07001319#endif /* IPLINK_IOCTL_COMPAT */
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001320
vadimk561e6502014-09-30 08:17:31 +03001321static void do_help(int argc, char **argv)
1322{
1323 struct link_util *lu = NULL;
1324
1325 if (argc <= 0) {
1326 usage();
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001327 return;
vadimk561e6502014-09-30 08:17:31 +03001328 }
1329
1330 lu = get_link_kind(*argv);
vadimk561e6502014-09-30 08:17:31 +03001331 if (lu && lu->print_help)
1332 lu->print_help(lu, argc-1, argv+1, stdout);
1333 else
1334 usage();
1335}
1336
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001337int do_iplink(int argc, char **argv)
1338{
Zhang Shengju6843d362015-08-14 03:13:41 +00001339 if (argc < 1)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001340 return ipaddr_list_link(0, NULL);
1341
Zhang Shengju6843d362015-08-14 03:13:41 +00001342 if (iplink_have_newlink()) {
1343 if (matches(*argv, "add") == 0)
1344 return iplink_modify(RTM_NEWLINK,
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001345 NLM_F_CREATE|NLM_F_EXCL,
1346 argc-1, argv+1);
Zhang Shengju6843d362015-08-14 03:13:41 +00001347 if (matches(*argv, "set") == 0 ||
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001348 matches(*argv, "change") == 0)
Zhang Shengju6843d362015-08-14 03:13:41 +00001349 return iplink_modify(RTM_NEWLINK, 0,
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001350 argc-1, argv+1);
Zhang Shengju6843d362015-08-14 03:13:41 +00001351 if (matches(*argv, "replace") == 0)
1352 return iplink_modify(RTM_NEWLINK,
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001353 NLM_F_CREATE|NLM_F_REPLACE,
1354 argc-1, argv+1);
Zhang Shengju6843d362015-08-14 03:13:41 +00001355 if (matches(*argv, "delete") == 0)
1356 return iplink_modify(RTM_DELLINK, 0,
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001357 argc-1, argv+1);
Zhang Shengju6843d362015-08-14 03:13:41 +00001358 } else {
1359#if IPLINK_IOCTL_COMPAT
1360 if (matches(*argv, "set") == 0)
1361 return do_set(argc-1, argv+1);
1362#endif
1363 }
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001364
Zhang Shengju6843d362015-08-14 03:13:41 +00001365 if (matches(*argv, "show") == 0 ||
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001366 matches(*argv, "lst") == 0 ||
1367 matches(*argv, "list") == 0)
Zhang Shengju6843d362015-08-14 03:13:41 +00001368 return ipaddr_list_link(argc-1, argv+1);
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001369
Zhang Shengju6843d362015-08-14 03:13:41 +00001370 if (matches(*argv, "help") == 0) {
1371 do_help(argc-1, argv+1);
1372 return 0;
1373 }
1374
1375 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n",
Stephen Hemminger6c5ffb92015-08-25 15:57:04 -07001376 *argv);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001377 exit(-1);
1378}