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