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