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