]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - ip/iplink.c
iproute2: add VF_PORT support
[lisovros/iproute2_canprio.git] / ip / iplink.c
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
40 static void usage(void) __attribute__((noreturn));
41 static int iplink_have_newlink(void);
42
43 void 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
91 static void usage(void)
92 {
93         iplink_usage();
94 }
95
96 static 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
102 static void *BODY;              /* cached dlopen(NULL) handle */
103 static struct link_util *linkutil_list;
104
105 struct 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
138 static int have_rtnl_newlink = -1;
139
140 static 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
153 static 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 */
175 static int iplink_have_newlink(void)
176 {
177         return 1;
178 }
179 #endif /* ! IPLINK_IOCTL_COMPAT */
180
181 struct iplink_req {
182         struct nlmsghdr         n;
183         struct ifinfomsg        i;
184         char                    buf[1024];
185 };
186
187 void 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
313 void 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
401 int 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
553 static 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
655 static 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
675 static 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
702 static 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
723 static 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
745 static 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
767 static 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
809 static 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
827 static 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
844 static 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
1007 int 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 }