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