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