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