1
2
3
4
5
6
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <unistd.h>
11#include <fcntl.h>
12#include <dlfcn.h>
13#include <errno.h>
14#include <string.h>
15#include <strings.h>
16#include <limits.h>
17
18#include <sys/socket.h>
19#include <arpa/inet.h>
20#include <linux/if.h>
21#include <linux/if_ether.h>
22
23#include "rt_names.h"
24#include "utils.h"
25#include "ip_common.h"
26#include "namespace.h"
27
28#ifndef GSO_MAX_SEGS
29#define GSO_MAX_SEGS 65535
30#endif
31
32
33static void usage(void) __attribute__((noreturn));
34
35void iplink_types_usage(void)
36{
37
38 fprintf(stderr,
39 "TYPE := { amt | bareudp | bond | bond_slave | bridge | bridge_slave |\n"
40 " dsa | dummy | erspan | geneve | gre | gretap | gtp | hsr |\n"
41 " ifb | ip6erspan | ip6gre | ip6gretap | ip6tnl |\n"
42 " ipip | ipoib | ipvlan | ipvtap |\n"
43 " macsec | macvlan | macvtap | netdevsim |\n"
44 " netkit | nlmon | pfcp | rmnet | sit | team | team_slave |\n"
45 " vcan | veth | vlan | vrf | vti | vxcan | vxlan | wwan |\n"
46 " xfrm | virt_wifi }\n");
47}
48
49void iplink_usage(void)
50{
51 fprintf(stderr,
52 "Usage: ip link add [link DEV | parentdev NAME] [ name ] NAME\n"
53 " [ txqueuelen PACKETS ]\n"
54 " [ address LLADDR ]\n"
55 " [ broadcast LLADDR ]\n"
56 " [ mtu MTU ] [index IDX ]\n"
57 " [ numtxqueues QUEUE_COUNT ]\n"
58 " [ numrxqueues QUEUE_COUNT ]\n"
59 " [ netns { PID | NETNSNAME | NETNSFILE } ]\n"
60 " type TYPE [ ARGS ]\n"
61 "\n"
62 " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"
63 "\n"
64 " ip link { set | change } { DEVICE | dev DEVICE | group DEVGROUP }\n"
65 " [ { up | down } ]\n"
66 " [ type TYPE ARGS ]\n");
67
68 fprintf(stderr,
69 " [ arp { on | off } ]\n"
70 " [ dynamic { on | off } ]\n"
71 " [ multicast { on | off } ]\n"
72 " [ allmulticast { on | off } ]\n"
73 " [ promisc { on | off } ]\n"
74 " [ trailers { on | off } ]\n"
75 " [ carrier { on | off } ]\n"
76 " [ txqueuelen PACKETS ]\n"
77 " [ name NEWNAME ]\n"
78 " [ address LLADDR ]\n"
79 " [ broadcast LLADDR ]\n"
80 " [ mtu MTU ]\n"
81 " [ netns { PID | NETNSNAME | NETNSFILE } ]\n"
82 " [ link-netns NAME | link-netnsid ID ]\n"
83 " [ alias NAME ]\n"
84 " [ vf NUM [ mac LLADDR ]\n"
85 " [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
86 " [ rate TXRATE ]\n"
87 " [ max_tx_rate TXRATE ]\n"
88 " [ min_tx_rate TXRATE ]\n"
89 " [ spoofchk { on | off} ]\n"
90 " [ query_rss { on | off} ]\n"
91 " [ state { auto | enable | disable} ]\n"
92 " [ trust { on | off} ]\n"
93 " [ node_guid EUI64 ]\n"
94 " [ port_guid EUI64 ] ]\n"
95 " [ { xdp | xdpgeneric | xdpdrv | xdpoffload } { off |\n"
96#ifdef HAVE_LIBBPF
97 " object FILE [ { section | program } NAME ] [ verbose ] |\n"
98#else
99 " object FILE [ section NAME ] [ verbose ] |\n"
100#endif
101 " pinned FILE } ]\n"
102 " [ master DEVICE ][ vrf NAME ]\n"
103 " [ nomaster ]\n"
104 " [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
105 " [ protodown { on | off } ]\n"
106 " [ protodown_reason PREASON { on | off } ]\n"
107 " [ gso_max_size BYTES ] [ gso_ipv4_max_size BYTES ] [ gso_max_segs PACKETS ]\n"
108 " [ gro_max_size BYTES ] [ gro_ipv4_max_size BYTES ]\n"
109 "\n"
110 " ip link show [ DEVICE | group GROUP ] [ { up | down } ] [master DEV] [vrf NAME]\n"
111 " [type TYPE] [nomaster] [ novf ]\n"
112 "\n"
113 " ip link xstats type TYPE [ ARGS ]\n"
114 "\n"
115 " ip link afstats [ dev DEVICE ]\n"
116 " ip link property add dev DEVICE [ altname NAME .. ]\n"
117 " ip link property del dev DEVICE [ altname NAME .. ]\n");
118
119 fprintf(stderr,
120 "\n"
121 " ip link help [ TYPE ]\n"
122 "\n");
123 iplink_types_usage();
124
125 exit(-1);
126}
127
128static void usage(void)
129{
130 iplink_usage();
131}
132
133static int on_off(const char *msg, const char *realval)
134{
135 fprintf(stderr,
136 "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n",
137 msg, realval);
138 return -1;
139}
140
141static void *BODY;
142static struct link_util *linkutil_list;
143
144struct link_util *get_link_kind(const char *id)
145{
146 void *dlh;
147 char buf[256];
148 struct link_util *l;
149
150 for (l = linkutil_list; l; l = l->next)
151 if (strcmp(l->id, id) == 0)
152 return l;
153
154 snprintf(buf, sizeof(buf), "%s/link_%s.so", get_ip_lib_dir(), id);
155 dlh = dlopen(buf, RTLD_LAZY);
156 if (dlh == NULL) {
157
158 dlh = BODY;
159 if (dlh == NULL) {
160 dlh = BODY = dlopen(NULL, RTLD_LAZY);
161 if (dlh == NULL)
162 return NULL;
163 }
164 }
165
166 snprintf(buf, sizeof(buf), "%s_link_util", id);
167 l = dlsym(dlh, buf);
168 if (l == NULL)
169 return NULL;
170
171 l->next = linkutil_list;
172 linkutil_list = l;
173 return l;
174}
175
176static int get_link_mode(const char *mode)
177{
178 if (strcasecmp(mode, "default") == 0)
179 return IF_LINK_MODE_DEFAULT;
180 if (strcasecmp(mode, "dormant") == 0)
181 return IF_LINK_MODE_DORMANT;
182 return -1;
183}
184
185static int get_addr_gen_mode(const char *mode)
186{
187 if (strcasecmp(mode, "eui64") == 0)
188 return IN6_ADDR_GEN_MODE_EUI64;
189 if (strcasecmp(mode, "none") == 0)
190 return IN6_ADDR_GEN_MODE_NONE;
191 if (strcasecmp(mode, "stable_secret") == 0)
192 return IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
193 if (strcasecmp(mode, "random") == 0)
194 return IN6_ADDR_GEN_MODE_RANDOM;
195 return -1;
196}
197
198static int nl_get_ll_addr_len(const char *ifname)
199{
200 int len;
201 int dev_index = ll_name_to_index(ifname);
202 struct iplink_req req = {
203 .n = {
204 .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
205 .nlmsg_type = RTM_GETLINK,
206 .nlmsg_flags = NLM_F_REQUEST
207 },
208 .i = {
209 .ifi_family = preferred_family,
210 .ifi_index = dev_index,
211 }
212 };
213 struct nlmsghdr *answer;
214 struct rtattr *tb[IFLA_MAX+1];
215
216 if (dev_index == 0)
217 return -1;
218
219 if (rtnl_talk(&rth, &req.n, &answer) < 0)
220 return -1;
221
222 len = answer->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
223 if (len < 0) {
224 free(answer);
225 return -1;
226 }
227
228 parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)),
229 len, NLA_F_NESTED);
230 if (!tb[IFLA_ADDRESS]) {
231 free(answer);
232 return -1;
233 }
234
235 len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
236 free(answer);
237 return len;
238}
239
240static int get_ifindex_in_netns(struct rtnl_handle *rtnl, int netnsid,
241 const char *ifname)
242{
243 struct {
244 struct nlmsghdr n;
245 struct ifinfomsg ifm;
246 char buf[1024];
247 } req = {
248 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
249 .n.nlmsg_flags = NLM_F_REQUEST,
250 .n.nlmsg_type = RTM_GETLINK,
251 };
252 struct nlmsghdr *answer;
253 int ifindex;
254
255 addattr32(&req.n, sizeof(req), IFLA_TARGET_NETNSID, netnsid);
256 addattr_l(&req.n, sizeof(req),
257 !check_ifname(ifname) ? IFLA_IFNAME : IFLA_ALT_IFNAME,
258 ifname, strlen(ifname) + 1);
259
260 if (rtnl_talk(rtnl, &req.n, &answer) < 0)
261 return 0;
262
263 if (answer->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
264 free(answer);
265 return 0;
266 }
267 ifindex = ((struct ifinfomsg *)NLMSG_DATA(answer))->ifi_index;
268 free(answer);
269 return ifindex;
270}
271
272static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
273 struct ifla_vf_vlan_info *ivvip)
274{
275 int argc = *argcp;
276 char **argv = *argvp;
277 unsigned int vci;
278
279 NEXT_ARG();
280 if (get_unsigned(&vci, *argv, 0) || vci > 4095)
281 invarg("Invalid \"vlan\" value\n", *argv);
282
283 ivvip->vlan = vci;
284 ivvip->vf = vf;
285 ivvip->qos = 0;
286 ivvip->vlan_proto = htons(ETH_P_8021Q);
287 if (NEXT_ARG_OK()) {
288 NEXT_ARG();
289 if (matches(*argv, "qos") == 0) {
290 NEXT_ARG();
291 if (get_unsigned(&ivvip->qos, *argv, 0))
292 invarg("Invalid \"qos\" value\n", *argv);
293 } else {
294
295 PREV_ARG();
296 }
297 }
298 if (NEXT_ARG_OK()) {
299 NEXT_ARG();
300 if (matches(*argv, "proto") == 0) {
301 NEXT_ARG();
302 if (ll_proto_a2n(&ivvip->vlan_proto, *argv))
303 invarg("protocol is invalid\n", *argv);
304 if (ivvip->vlan_proto != htons(ETH_P_8021AD) &&
305 ivvip->vlan_proto != htons(ETH_P_8021Q)) {
306 SPRINT_BUF(b1);
307 SPRINT_BUF(b2);
308 char msg[64 + sizeof(b1) + sizeof(b2)];
309
310 sprintf(msg,
311 "Invalid \"vlan protocol\" value - supported %s, %s\n",
312 ll_proto_n2a(htons(ETH_P_8021Q),
313 b1, sizeof(b1)),
314 ll_proto_n2a(htons(ETH_P_8021AD),
315 b2, sizeof(b2)));
316 invarg(msg, *argv);
317 }
318 } else {
319
320 PREV_ARG();
321 }
322 }
323
324 *argcp = argc;
325 *argvp = argv;
326}
327
328static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
329 struct iplink_req *req, const char *dev)
330{
331 char new_rate_api = 0, count = 0, override_legacy_rate = 0;
332 struct ifla_vf_rate tivt;
333 int len, argc = *argcp;
334 char **argv = *argvp;
335 struct rtattr *vfinfo;
336 int ret;
337
338 tivt.min_tx_rate = -1;
339 tivt.max_tx_rate = -1;
340
341 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
342
343 while (NEXT_ARG_OK()) {
344 NEXT_ARG();
345 count++;
346 if (!matches(*argv, "max_tx_rate")) {
347
348 new_rate_api = 1;
349
350 override_legacy_rate = 1;
351 } else if (!matches(*argv, "min_tx_rate")) {
352
353 new_rate_api = 1;
354 }
355 }
356
357 while (count--) {
358
359 PREV_ARG();
360 }
361
362 while (NEXT_ARG_OK()) {
363 NEXT_ARG();
364 if (matches(*argv, "mac") == 0) {
365 struct ifla_vf_mac ivm = { 0 };
366 int halen = nl_get_ll_addr_len(dev);
367
368 NEXT_ARG();
369 ivm.vf = vf;
370 len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
371 if (len < 0)
372 return -1;
373 if (halen > 0 && len != halen) {
374 fprintf(stderr,
375 "Invalid address length %d - must be %d bytes\n",
376 len, halen);
377 return -1;
378 }
379 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
380 &ivm, sizeof(ivm));
381 } else if (matches(*argv, "vlan") == 0) {
382 struct ifla_vf_vlan_info ivvi;
383
384 iplink_parse_vf_vlan_info(vf, &argc, &argv, &ivvi);
385
386 if (ivvi.vlan_proto == htons(ETH_P_8021Q)) {
387 struct ifla_vf_vlan ivv;
388
389 ivv.vf = ivvi.vf;
390 ivv.vlan = ivvi.vlan;
391 ivv.qos = ivvi.qos;
392 addattr_l(&req->n, sizeof(*req),
393 IFLA_VF_VLAN, &ivv, sizeof(ivv));
394 } else {
395 struct rtattr *vfvlanlist;
396
397 vfvlanlist = addattr_nest(&req->n, sizeof(*req),
398 IFLA_VF_VLAN_LIST);
399 addattr_l(&req->n, sizeof(*req),
400 IFLA_VF_VLAN_INFO, &ivvi,
401 sizeof(ivvi));
402
403 while (NEXT_ARG_OK()) {
404 NEXT_ARG();
405 if (matches(*argv, "vlan") != 0) {
406 PREV_ARG();
407 break;
408 }
409 iplink_parse_vf_vlan_info(vf, &argc,
410 &argv, &ivvi);
411 addattr_l(&req->n, sizeof(*req),
412 IFLA_VF_VLAN_INFO, &ivvi,
413 sizeof(ivvi));
414 }
415 addattr_nest_end(&req->n, vfvlanlist);
416 }
417 } else if (matches(*argv, "rate") == 0) {
418 struct ifla_vf_tx_rate ivt;
419
420 NEXT_ARG();
421 if (get_unsigned(&ivt.rate, *argv, 0))
422 invarg("Invalid \"rate\" value\n", *argv);
423
424 ivt.vf = vf;
425 if (!new_rate_api)
426 addattr_l(&req->n, sizeof(*req),
427 IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
428 else if (!override_legacy_rate)
429 tivt.max_tx_rate = ivt.rate;
430
431 } else if (matches(*argv, "max_tx_rate") == 0) {
432 NEXT_ARG();
433 if (get_unsigned(&tivt.max_tx_rate, *argv, 0))
434 invarg("Invalid \"max tx rate\" value\n",
435 *argv);
436 tivt.vf = vf;
437
438 } else if (matches(*argv, "min_tx_rate") == 0) {
439 NEXT_ARG();
440 if (get_unsigned(&tivt.min_tx_rate, *argv, 0))
441 invarg("Invalid \"min tx rate\" value\n",
442 *argv);
443 tivt.vf = vf;
444
445 } else if (matches(*argv, "spoofchk") == 0) {
446 struct ifla_vf_spoofchk ivs;
447
448 NEXT_ARG();
449 ivs.setting = parse_on_off("spoofchk", *argv, &ret);
450 if (ret)
451 return ret;
452 ivs.vf = vf;
453 addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK,
454 &ivs, sizeof(ivs));
455
456 } else if (matches(*argv, "query_rss") == 0) {
457 struct ifla_vf_rss_query_en ivs;
458
459 NEXT_ARG();
460 ivs.setting = parse_on_off("query_rss", *argv, &ret);
461 if (ret)
462 return ret;
463 ivs.vf = vf;
464 addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN,
465 &ivs, sizeof(ivs));
466
467 } else if (matches(*argv, "trust") == 0) {
468 struct ifla_vf_trust ivt;
469
470 NEXT_ARG();
471 ivt.setting = parse_on_off("trust", *argv, &ret);
472 if (ret)
473 return ret;
474 ivt.vf = vf;
475 addattr_l(&req->n, sizeof(*req), IFLA_VF_TRUST,
476 &ivt, sizeof(ivt));
477
478 } else if (matches(*argv, "state") == 0) {
479 struct ifla_vf_link_state ivl;
480
481 NEXT_ARG();
482 if (matches(*argv, "auto") == 0)
483 ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
484 else if (matches(*argv, "enable") == 0)
485 ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
486 else if (matches(*argv, "disable") == 0)
487 ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
488 else
489 invarg("Invalid \"state\" value\n", *argv);
490 ivl.vf = vf;
491 addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE,
492 &ivl, sizeof(ivl));
493 } else if (matches(*argv, "node_guid") == 0) {
494 struct ifla_vf_guid ivg;
495
496 NEXT_ARG();
497 ivg.vf = vf;
498 if (get_guid(&ivg.guid, *argv)) {
499 invarg("Invalid GUID format\n", *argv);
500 return -1;
501 }
502 addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_NODE_GUID,
503 &ivg, sizeof(ivg));
504 } else if (matches(*argv, "port_guid") == 0) {
505 struct ifla_vf_guid ivg;
506
507 NEXT_ARG();
508 ivg.vf = vf;
509 if (get_guid(&ivg.guid, *argv)) {
510 invarg("Invalid GUID format\n", *argv);
511 return -1;
512 }
513 addattr_l(&req->n, sizeof(*req), IFLA_VF_IB_PORT_GUID,
514 &ivg, sizeof(ivg));
515 } else {
516
517 PREV_ARG();
518 break;
519 }
520 }
521
522 if (new_rate_api) {
523 int tmin, tmax;
524
525 if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
526 ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev);
527 if (tivt.min_tx_rate == -1)
528 tivt.min_tx_rate = tmin;
529 if (tivt.max_tx_rate == -1)
530 tivt.max_tx_rate = tmax;
531 }
532
533 if (tivt.max_tx_rate && tivt.min_tx_rate > tivt.max_tx_rate) {
534 fprintf(stderr,
535 "Invalid min_tx_rate %d - must be <= max_tx_rate %d\n",
536 tivt.min_tx_rate, tivt.max_tx_rate);
537 return -1;
538 }
539
540 addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
541 sizeof(tivt));
542 }
543
544 if (argc == *argcp)
545 incomplete_command();
546
547 addattr_nest_end(&req->n, vfinfo);
548
549 *argcp = argc;
550 *argvp = argv;
551 return 0;
552}
553
554int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
555{
556 bool move_netns = false;
557 char *name = NULL;
558 char *dev = NULL;
559 char *link = NULL;
560 int ret, len;
561 char abuf[32];
562 int qlen = -1;
563 int mtu = -1;
564 int netns = -1;
565 int vf = -1;
566 int numtxqueues = -1;
567 int numrxqueues = -1;
568 char *link_netns = NULL;
569 int link_netnsid = -1;
570 struct rtnl_handle netns_rtnl;
571 struct rtnl_handle *rtnl = &rth;
572 int index = 0;
573 int group = -1;
574 int addr_len = 0;
575 int err;
576
577 ret = argc;
578
579 while (argc > 0) {
580 if (strcmp(*argv, "up") == 0) {
581 req->i.ifi_change |= IFF_UP;
582 req->i.ifi_flags |= IFF_UP;
583 } else if (strcmp(*argv, "down") == 0) {
584 req->i.ifi_change |= IFF_UP;
585 req->i.ifi_flags &= ~IFF_UP;
586 } else if (strcmp(*argv, "name") == 0) {
587 NEXT_ARG();
588 if (name)
589 duparg("name", *argv);
590 if (check_ifname(*argv))
591 invarg("\"name\" not a valid ifname", *argv);
592 name = *argv;
593 if (!dev)
594 dev = name;
595 } else if (strcmp(*argv, "index") == 0) {
596 NEXT_ARG();
597 if (index)
598 duparg("index", *argv);
599 index = atoi(*argv);
600 if (index <= 0)
601 invarg("Invalid \"index\" value", *argv);
602 } else if (matches(*argv, "link") == 0) {
603 NEXT_ARG();
604 link = *argv;
605 } else if (matches(*argv, "address") == 0) {
606 NEXT_ARG();
607 addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
608 if (addr_len < 0)
609 return -1;
610 addattr_l(&req->n, sizeof(*req),
611 IFLA_ADDRESS, abuf, addr_len);
612 } else if (matches(*argv, "broadcast") == 0 ||
613 strcmp(*argv, "brd") == 0) {
614 NEXT_ARG();
615 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
616 if (len < 0)
617 return -1;
618 addattr_l(&req->n, sizeof(*req),
619 IFLA_BROADCAST, abuf, len);
620 } else if (matches(*argv, "txqueuelen") == 0 ||
621 strcmp(*argv, "qlen") == 0 ||
622 matches(*argv, "txqlen") == 0) {
623 NEXT_ARG();
624 if (qlen != -1)
625 duparg("txqueuelen", *argv);
626 if (get_integer(&qlen, *argv, 0))
627 invarg("Invalid \"txqueuelen\" value\n", *argv);
628 addattr_l(&req->n, sizeof(*req),
629 IFLA_TXQLEN, &qlen, 4);
630 } else if (strcmp(*argv, "mtu") == 0) {
631 NEXT_ARG();
632 if (mtu != -1)
633 duparg("mtu", *argv);
634 if (get_integer(&mtu, *argv, 0))
635 invarg("Invalid \"mtu\" value\n", *argv);
636 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
637 } else if (strcmp(*argv, "xdpgeneric") == 0 ||
638 strcmp(*argv, "xdpdrv") == 0 ||
639 strcmp(*argv, "xdpoffload") == 0 ||
640 strcmp(*argv, "xdp") == 0) {
641 bool generic = strcmp(*argv, "xdpgeneric") == 0;
642 bool drv = strcmp(*argv, "xdpdrv") == 0;
643 bool offload = strcmp(*argv, "xdpoffload") == 0;
644
645 NEXT_ARG();
646 if (xdp_parse(&argc, &argv, req, dev,
647 generic, drv, offload))
648 exit(-1);
649
650 if (offload && name == dev)
651 dev = NULL;
652 } else if (strcmp(*argv, "netns") == 0) {
653 int pid;
654
655 NEXT_ARG();
656 if (netns != -1)
657 duparg("netns", *argv);
658 netns = netns_get_fd(*argv);
659 if (netns < 0 && get_integer(&pid, *argv, 0) == 0) {
660 char path[PATH_MAX];
661
662 snprintf(path, sizeof(path), "/proc/%d/ns/net",
663 pid);
664 netns = open(path, O_RDONLY);
665 }
666 if (netns < 0)
667 invarg("Invalid \"netns\" value\n", *argv);
668
669 open_fds_add(netns);
670 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
671 &netns, 4);
672 move_netns = true;
673 } else if (strcmp(*argv, "multicast") == 0) {
674 NEXT_ARG();
675 req->i.ifi_change |= IFF_MULTICAST;
676
677 if (strcmp(*argv, "on") == 0)
678 req->i.ifi_flags |= IFF_MULTICAST;
679 else if (strcmp(*argv, "off") == 0)
680 req->i.ifi_flags &= ~IFF_MULTICAST;
681 else
682 return on_off("multicast", *argv);
683 } else if (strcmp(*argv, "allmulticast") == 0) {
684 NEXT_ARG();
685 req->i.ifi_change |= IFF_ALLMULTI;
686
687 if (strcmp(*argv, "on") == 0)
688 req->i.ifi_flags |= IFF_ALLMULTI;
689 else if (strcmp(*argv, "off") == 0)
690 req->i.ifi_flags &= ~IFF_ALLMULTI;
691 else
692 return on_off("allmulticast", *argv);
693 } else if (strcmp(*argv, "promisc") == 0) {
694 NEXT_ARG();
695 req->i.ifi_change |= IFF_PROMISC;
696
697 if (strcmp(*argv, "on") == 0)
698 req->i.ifi_flags |= IFF_PROMISC;
699 else if (strcmp(*argv, "off") == 0)
700 req->i.ifi_flags &= ~IFF_PROMISC;
701 else
702 return on_off("promisc", *argv);
703 } else if (strcmp(*argv, "trailers") == 0) {
704 NEXT_ARG();
705 req->i.ifi_change |= IFF_NOTRAILERS;
706
707 if (strcmp(*argv, "off") == 0)
708 req->i.ifi_flags |= IFF_NOTRAILERS;
709 else if (strcmp(*argv, "on") == 0)
710 req->i.ifi_flags &= ~IFF_NOTRAILERS;
711 else
712 return on_off("trailers", *argv);
713 } else if (strcmp(*argv, "arp") == 0) {
714 NEXT_ARG();
715 req->i.ifi_change |= IFF_NOARP;
716
717 if (strcmp(*argv, "on") == 0)
718 req->i.ifi_flags &= ~IFF_NOARP;
719 else if (strcmp(*argv, "off") == 0)
720 req->i.ifi_flags |= IFF_NOARP;
721 else
722 return on_off("arp", *argv);
723 } else if (strcmp(*argv, "carrier") == 0) {
724 int carrier;
725
726 NEXT_ARG();
727 carrier = parse_on_off("carrier", *argv, &err);
728 if (err)
729 return err;
730
731 addattr8(&req->n, sizeof(*req), IFLA_CARRIER, carrier);
732 } else if (strcmp(*argv, "vf") == 0) {
733 struct rtattr *vflist;
734
735 NEXT_ARG();
736 if (get_integer(&vf, *argv, 0))
737 invarg("Invalid \"vf\" value\n", *argv);
738
739 vflist = addattr_nest(&req->n, sizeof(*req),
740 IFLA_VFINFO_LIST);
741 if (!dev)
742 missarg("dev");
743
744 len = iplink_parse_vf(vf, &argc, &argv, req, dev);
745 if (len < 0)
746 return -1;
747 addattr_nest_end(&req->n, vflist);
748
749 if (name == dev)
750 dev = NULL;
751 } else if (matches(*argv, "master") == 0) {
752 int ifindex;
753
754 NEXT_ARG();
755 ifindex = ll_name_to_index(*argv);
756 if (!ifindex)
757 invarg("Device does not exist\n", *argv);
758 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
759 &ifindex, 4);
760 } else if (strcmp(*argv, "vrf") == 0) {
761 int ifindex;
762
763 NEXT_ARG();
764 ifindex = ll_name_to_index(*argv);
765 if (!ifindex)
766 invarg("Not a valid VRF name\n", *argv);
767 if (!name_is_vrf(*argv))
768 invarg("Not a valid VRF name\n", *argv);
769 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
770 &ifindex, sizeof(ifindex));
771 } else if (matches(*argv, "nomaster") == 0) {
772 int ifindex = 0;
773
774 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
775 &ifindex, 4);
776 } else if (matches(*argv, "dynamic") == 0) {
777 NEXT_ARG();
778 req->i.ifi_change |= IFF_DYNAMIC;
779
780 if (strcmp(*argv, "on") == 0)
781 req->i.ifi_flags |= IFF_DYNAMIC;
782 else if (strcmp(*argv, "off") == 0)
783 req->i.ifi_flags &= ~IFF_DYNAMIC;
784 else
785 return on_off("dynamic", *argv);
786 } else if (matches(*argv, "type") == 0) {
787 NEXT_ARG();
788 *type = *argv;
789 argc--; argv++;
790 break;
791 } else if (matches(*argv, "alias") == 0) {
792 NEXT_ARG();
793 len = strlen(*argv);
794 if (len >= IFALIASZ)
795 invarg("alias too long\n", *argv);
796 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
797 *argv, len);
798 } else if (strcmp(*argv, "group") == 0) {
799 NEXT_ARG();
800 if (group != -1)
801 duparg("group", *argv);
802 if (rtnl_group_a2n(&group, *argv))
803 invarg("Invalid \"group\" value\n", *argv);
804 addattr32(&req->n, sizeof(*req), IFLA_GROUP, group);
805 } else if (strcmp(*argv, "mode") == 0) {
806 int mode;
807
808 NEXT_ARG();
809 mode = get_link_mode(*argv);
810 if (mode < 0)
811 invarg("Invalid link mode\n", *argv);
812 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
813 } else if (strcmp(*argv, "state") == 0) {
814 int state;
815
816 NEXT_ARG();
817 state = get_operstate(*argv);
818 if (state < 0)
819 invarg("Invalid operstate\n", *argv);
820
821 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
822 } else if (matches(*argv, "numtxqueues") == 0) {
823 NEXT_ARG();
824 if (numtxqueues != -1)
825 duparg("numtxqueues", *argv);
826 if (get_integer(&numtxqueues, *argv, 0))
827 invarg("Invalid \"numtxqueues\" value\n",
828 *argv);
829 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
830 &numtxqueues, 4);
831 } else if (matches(*argv, "numrxqueues") == 0) {
832 NEXT_ARG();
833 if (numrxqueues != -1)
834 duparg("numrxqueues", *argv);
835 if (get_integer(&numrxqueues, *argv, 0))
836 invarg("Invalid \"numrxqueues\" value\n",
837 *argv);
838 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
839 &numrxqueues, 4);
840 } else if (matches(*argv, "addrgenmode") == 0) {
841 struct rtattr *afs, *afs6;
842 int mode;
843
844 NEXT_ARG();
845 mode = get_addr_gen_mode(*argv);
846 if (mode < 0)
847 invarg("Invalid address generation mode\n",
848 *argv);
849 afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
850 afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
851 addattr8(&req->n, sizeof(*req),
852 IFLA_INET6_ADDR_GEN_MODE, mode);
853 addattr_nest_end(&req->n, afs6);
854 addattr_nest_end(&req->n, afs);
855 } else if (matches(*argv, "link-netns") == 0) {
856 NEXT_ARG();
857 if (link_netnsid != -1 || link_netns)
858 duparg("link-netns/link-netnsid", *argv);
859 link_netns = *argv;
860 } else if (matches(*argv, "link-netnsid") == 0) {
861 NEXT_ARG();
862 if (link_netnsid != -1 || link_netns)
863 duparg("link-netns/link-netnsid", *argv);
864 if (get_integer(&link_netnsid, *argv, 0))
865 invarg("Invalid \"link-netnsid\" value\n",
866 *argv);
867 addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
868 link_netnsid);
869 } else if (strcmp(*argv, "protodown") == 0) {
870 unsigned int proto_down;
871
872 NEXT_ARG();
873 proto_down = parse_on_off("protodown", *argv, &err);
874 if (err)
875 return err;
876 addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
877 proto_down);
878 } else if (strcmp(*argv, "protodown_reason") == 0) {
879 struct rtattr *pr;
880 __u32 preason = 0, prvalue = 0, prmask = 0;
881
882 NEXT_ARG();
883 if (protodown_reason_a2n(&preason, *argv))
884 invarg("invalid protodown reason\n", *argv);
885 NEXT_ARG();
886 prmask = 1 << preason;
887 if (matches(*argv, "on") == 0)
888 prvalue |= prmask;
889 else if (matches(*argv, "off") == 0)
890 prvalue &= ~prmask;
891 else
892 return on_off("protodown_reason", *argv);
893 pr = addattr_nest(&req->n, sizeof(*req),
894 IFLA_PROTO_DOWN_REASON | NLA_F_NESTED);
895 addattr32(&req->n, sizeof(*req),
896 IFLA_PROTO_DOWN_REASON_MASK, prmask);
897 addattr32(&req->n, sizeof(*req),
898 IFLA_PROTO_DOWN_REASON_VALUE, prvalue);
899 addattr_nest_end(&req->n, pr);
900 } else if (strcmp(*argv, "gso_max_size") == 0) {
901 unsigned int max_size;
902
903 NEXT_ARG();
904 if (get_unsigned(&max_size, *argv, 0))
905 invarg("Invalid \"gso_max_size\" value\n",
906 *argv);
907 addattr32(&req->n, sizeof(*req),
908 IFLA_GSO_MAX_SIZE, max_size);
909 } else if (strcmp(*argv, "gso_max_segs") == 0) {
910 unsigned int max_segs;
911
912 NEXT_ARG();
913 if (get_unsigned(&max_segs, *argv, 0) ||
914 max_segs > GSO_MAX_SEGS)
915 invarg("Invalid \"gso_max_segs\" value\n",
916 *argv);
917 addattr32(&req->n, sizeof(*req),
918 IFLA_GSO_MAX_SEGS, max_segs);
919 } else if (strcmp(*argv, "gro_max_size") == 0) {
920 unsigned int max_size;
921
922 NEXT_ARG();
923 if (get_unsigned(&max_size, *argv, 0))
924 invarg("Invalid \"gro_max_size\" value\n",
925 *argv);
926 addattr32(&req->n, sizeof(*req),
927 IFLA_GRO_MAX_SIZE, max_size);
928 } else if (strcmp(*argv, "gso_ipv4_max_size") == 0) {
929 unsigned int max_size;
930
931 NEXT_ARG();
932 if (get_unsigned(&max_size, *argv, 0))
933 invarg("Invalid \"gso_ipv4_max_size\" value\n",
934 *argv);
935 addattr32(&req->n, sizeof(*req),
936 IFLA_GSO_IPV4_MAX_SIZE, max_size);
937 } else if (strcmp(*argv, "gro_ipv4_max_size") == 0) {
938 unsigned int max_size;
939
940 NEXT_ARG();
941 if (get_unsigned(&max_size, *argv, 0))
942 invarg("Invalid \"gro_ipv4_max_size\" value\n",
943 *argv);
944 addattr32(&req->n, sizeof(*req),
945 IFLA_GRO_IPV4_MAX_SIZE, max_size);
946 } else if (strcmp(*argv, "parentdev") == 0) {
947 NEXT_ARG();
948 addattr_l(&req->n, sizeof(*req), IFLA_PARENT_DEV_NAME,
949 *argv, strlen(*argv) + 1);
950 } else {
951 if (matches(*argv, "help") == 0)
952 usage();
953
954 if (strcmp(*argv, "dev") == 0)
955 NEXT_ARG();
956 if (dev != name)
957 duparg2("dev", *argv);
958 if (check_altifname(*argv))
959 invarg("\"dev\" not a valid ifname", *argv);
960 dev = *argv;
961 }
962 argc--; argv++;
963 }
964
965 ret -= argc;
966
967
968 if (!name)
969 name = dev;
970 else if (!dev)
971 dev = name;
972 else if (!strcmp(name, dev))
973 name = dev;
974
975 if (dev && addr_len &&
976 !(req->n.nlmsg_flags & NLM_F_CREATE)) {
977 int halen = nl_get_ll_addr_len(dev);
978
979 if (halen >= 0 && halen != addr_len) {
980 fprintf(stderr,
981 "Invalid address length %d - must be %d bytes\n",
982 addr_len, halen);
983 return -1;
984 }
985 }
986
987 if (index &&
988 (!(req->n.nlmsg_flags & NLM_F_CREATE) &&
989 !move_netns)) {
990 fprintf(stderr,
991 "index can be used only when creating devices or when moving device to another netns.\n");
992 exit(-1);
993 }
994
995 if (group != -1) {
996 if (!dev) {
997 if (argc) {
998 fprintf(stderr,
999 "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
1000 *argv);
1001 exit(-1);
1002 }
1003 if (req->n.nlmsg_flags & NLM_F_CREATE) {
1004 fprintf(stderr,
1005 "group cannot be used when creating devices.\n");
1006 exit(-1);
1007 }
1008
1009 *type = NULL;
1010 return ret;
1011 }
1012 }
1013
1014 if (netns != -1 && (link_netnsid != -1 || link_netns)) {
1015 int orig_netns;
1016
1017
1018
1019
1020
1021
1022
1023 orig_netns = open("/proc/self/ns/net", O_RDONLY);
1024 if (orig_netns == -1) {
1025 fprintf(stderr, "Cannot open namespace: %s\n",
1026 strerror(errno));
1027 exit(-1);
1028 }
1029 if (setns(netns, CLONE_NEWNET) < 0) {
1030 fprintf(stderr, "Cannot set namespace: %s\n",
1031 strerror(errno));
1032 exit(-1);
1033 }
1034 if (rtnl_open(&netns_rtnl, 0) < 0) {
1035 fprintf(stderr, "Cannot open rtnetlink\n");
1036 exit(-1);
1037 }
1038 if (setns(orig_netns, CLONE_NEWNET) < 0) {
1039 fprintf(stderr, "Cannot set namespace: %s\n",
1040 strerror(errno));
1041 exit(-1);
1042 }
1043 close(orig_netns);
1044 rtnl = &netns_rtnl;
1045 }
1046
1047 if (link_netns) {
1048 link_netnsid = netns_id_from_name(rtnl, link_netns);
1049
1050 if (link_netnsid < 0) {
1051 set_netns_id_from_name(rtnl, link_netns, -1);
1052 link_netnsid = netns_id_from_name(rtnl, link_netns);
1053 }
1054 if (link_netnsid < 0)
1055 invarg("Invalid \"link-netns\" value\n",
1056 *argv);
1057 addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
1058 link_netnsid);
1059 }
1060
1061 if (!(req->n.nlmsg_flags & NLM_F_CREATE)) {
1062 if (!dev) {
1063 fprintf(stderr,
1064 "Not enough information: \"dev\" argument is required.\n");
1065 exit(-1);
1066 }
1067
1068 req->i.ifi_index = ll_name_to_index(dev);
1069 if (!req->i.ifi_index) {
1070 ret = nodev(dev);
1071 goto out;
1072 }
1073
1074
1075 if (name == dev)
1076 name = NULL;
1077
1078 if (index)
1079 addattr32(&req->n, sizeof(*req), IFLA_NEW_IFINDEX, index);
1080 } else {
1081 if (name != dev) {
1082 fprintf(stderr,
1083 "both \"name\" and \"dev\" cannot be used when creating devices.\n");
1084 exit(-1);
1085 }
1086
1087 if (link) {
1088 int ifindex;
1089
1090 if (link_netnsid == -1)
1091 ifindex = ll_name_to_index(link);
1092 else
1093 ifindex = get_ifindex_in_netns(rtnl,
1094 link_netnsid,
1095 link);
1096
1097 if (!ifindex) {
1098 ret = nodev(link);
1099 goto out;
1100 }
1101 addattr32(&req->n, sizeof(*req), IFLA_LINK, ifindex);
1102 }
1103
1104 req->i.ifi_index = index;
1105 }
1106
1107 if (name) {
1108 addattr_l(&req->n, sizeof(*req),
1109 IFLA_IFNAME, name, strlen(name) + 1);
1110 }
1111
1112out:
1113 if (rtnl == &netns_rtnl)
1114 rtnl_close(rtnl);
1115
1116 return ret;
1117}
1118
1119static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
1120{
1121 char *type = NULL;
1122 struct iplink_req req = {
1123 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
1124 .n.nlmsg_flags = NLM_F_REQUEST | flags,
1125 .n.nlmsg_type = cmd,
1126 .i.ifi_family = preferred_family,
1127 };
1128 int ret;
1129
1130 ret = iplink_parse(argc, argv, &req, &type);
1131 if (ret < 0)
1132 return ret;
1133
1134 if (type) {
1135 struct link_util *lu;
1136 struct rtattr *linkinfo;
1137 char *ulinep = strchr(type, '_');
1138 int iflatype;
1139
1140 linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
1141 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
1142 strlen(type));
1143
1144 lu = get_link_kind(type);
1145 if (ulinep && !strcmp(ulinep, "_slave"))
1146 iflatype = IFLA_INFO_SLAVE_DATA;
1147 else
1148 iflatype = IFLA_INFO_DATA;
1149
1150 argc -= ret;
1151 argv += ret;
1152
1153 if (lu && lu->parse_opt && argc) {
1154 struct rtattr *data;
1155
1156 data = addattr_nest(&req.n, sizeof(req), iflatype);
1157
1158 if (lu->parse_opt(lu, argc, argv, &req.n))
1159 return -1;
1160
1161 addattr_nest_end(&req.n, data);
1162 } else if (argc) {
1163 if (matches(*argv, "help") == 0)
1164 usage();
1165 fprintf(stderr,
1166 "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
1167 *argv);
1168 return -1;
1169 }
1170 addattr_nest_end(&req.n, linkinfo);
1171 } else if (flags & NLM_F_CREATE) {
1172 fprintf(stderr,
1173 "Not enough information: \"type\" argument is required\n");
1174 return -1;
1175 }
1176
1177 if (echo_request)
1178 ret = rtnl_echo_talk(&rth, &req.n, json, print_linkinfo);
1179 else
1180 ret = rtnl_talk(&rth, &req.n, NULL);
1181
1182 open_fds_close();
1183
1184 if (ret)
1185 return -2;
1186
1187
1188 ll_drop_by_index(req.i.ifi_index);
1189
1190 return 0;
1191}
1192
1193int iplink_get(char *name, __u32 filt_mask)
1194{
1195 struct iplink_req req = {
1196 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
1197 .n.nlmsg_flags = NLM_F_REQUEST,
1198 .n.nlmsg_type = RTM_GETLINK,
1199 .i.ifi_family = preferred_family,
1200 };
1201 struct nlmsghdr *answer;
1202
1203 if (name) {
1204 addattr_l(&req.n, sizeof(req),
1205 !check_ifname(name) ? IFLA_IFNAME : IFLA_ALT_IFNAME,
1206 name, strlen(name) + 1);
1207 }
1208
1209 if (!show_stats)
1210 filt_mask |= RTEXT_FILTER_SKIP_STATS;
1211 addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
1212
1213 if (rtnl_talk(&rth, &req.n, &answer) < 0)
1214 return -2;
1215
1216 open_json_object(NULL);
1217 print_linkinfo(answer, stdout);
1218 close_json_object();
1219
1220 free(answer);
1221 return 0;
1222}
1223
1224
1225void print_mpls_link_stats(FILE *fp, const struct mpls_link_stats *stats,
1226 const char *indent)
1227{
1228 unsigned int cols[] = {
1229 strlen("*X: bytes"),
1230 strlen("packets"),
1231 strlen("errors"),
1232 strlen("dropped"),
1233 strlen("noroute"),
1234 };
1235
1236 if (is_json_context()) {
1237
1238 open_json_object("rx");
1239 print_u64(PRINT_JSON, "bytes", NULL, stats->rx_bytes);
1240 print_u64(PRINT_JSON, "packets", NULL, stats->rx_packets);
1241 print_u64(PRINT_JSON, "errors", NULL, stats->rx_errors);
1242 print_u64(PRINT_JSON, "dropped", NULL, stats->rx_dropped);
1243 print_u64(PRINT_JSON, "noroute", NULL, stats->rx_noroute);
1244 close_json_object();
1245
1246
1247 open_json_object("tx");
1248 print_u64(PRINT_JSON, "bytes", NULL, stats->tx_bytes);
1249 print_u64(PRINT_JSON, "packets", NULL, stats->tx_packets);
1250 print_u64(PRINT_JSON, "errors", NULL, stats->tx_errors);
1251 print_u64(PRINT_JSON, "dropped", NULL, stats->tx_dropped);
1252 close_json_object();
1253 } else {
1254 size_columns(cols, ARRAY_SIZE(cols), stats->rx_bytes,
1255 stats->rx_packets, stats->rx_errors,
1256 stats->rx_dropped, stats->rx_noroute);
1257 size_columns(cols, ARRAY_SIZE(cols), stats->tx_bytes,
1258 stats->tx_packets, stats->tx_errors,
1259 stats->tx_dropped, 0);
1260
1261 fprintf(fp, "%sRX: %*s %*s %*s %*s %*s%s", indent,
1262 cols[0] - 4, "bytes", cols[1], "packets",
1263 cols[2], "errors", cols[3], "dropped",
1264 cols[4], "noroute", _SL_);
1265 fprintf(fp, "%s", indent);
1266 print_num(fp, cols[0], stats->rx_bytes);
1267 print_num(fp, cols[1], stats->rx_packets);
1268 print_num(fp, cols[2], stats->rx_errors);
1269 print_num(fp, cols[3], stats->rx_dropped);
1270 print_num(fp, cols[4], stats->rx_noroute);
1271 print_nl();
1272
1273 fprintf(fp, "%sTX: %*s %*s %*s %*s%s", indent,
1274 cols[0] - 4, "bytes", cols[1], "packets",
1275 cols[2], "errors", cols[3], "dropped", _SL_);
1276 fprintf(fp, "%s", indent);
1277 print_num(fp, cols[0], stats->tx_bytes);
1278 print_num(fp, cols[1], stats->tx_packets);
1279 print_num(fp, cols[2], stats->tx_errors);
1280 print_num(fp, cols[3], stats->tx_dropped);
1281 }
1282}
1283
1284static void print_mpls_stats(FILE *fp, struct rtattr *attr)
1285{
1286 struct rtattr *mrtb[MPLS_STATS_MAX+1];
1287 struct mpls_link_stats *stats;
1288
1289 parse_rtattr(mrtb, MPLS_STATS_MAX, RTA_DATA(attr),
1290 RTA_PAYLOAD(attr));
1291 if (!mrtb[MPLS_STATS_LINK])
1292 return;
1293
1294 stats = RTA_DATA(mrtb[MPLS_STATS_LINK]);
1295 print_string(PRINT_FP, NULL, " mpls:", NULL);
1296 print_nl();
1297 print_mpls_link_stats(fp, stats, " ");
1298 print_string(PRINT_FP, NULL, "%s", "\n");
1299 fflush(fp);
1300}
1301
1302static void print_af_stats_attr(FILE *fp, int ifindex, struct rtattr *attr)
1303{
1304 bool if_printed = false;
1305 struct rtattr *i;
1306 int rem;
1307
1308 rem = RTA_PAYLOAD(attr);
1309 for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
1310 if (preferred_family != AF_UNSPEC &&
1311 i->rta_type != preferred_family)
1312 continue;
1313
1314 if (!if_printed) {
1315 print_uint(PRINT_ANY, "ifindex",
1316 "%u:", ifindex);
1317 print_color_string(PRINT_ANY, COLOR_IFNAME,
1318 "ifname", "%s",
1319 ll_index_to_name(ifindex));
1320 print_nl();
1321 if_printed = true;
1322 }
1323
1324 switch (i->rta_type) {
1325 case AF_MPLS:
1326 print_mpls_stats(fp, i);
1327 break;
1328 default:
1329 fprintf(stderr, " unknown af(%d)\n", i->rta_type);
1330 break;
1331 }
1332 }
1333}
1334
1335struct af_stats_ctx {
1336 FILE *fp;
1337 int ifindex;
1338};
1339
1340static int print_af_stats(struct nlmsghdr *n, void *arg)
1341{
1342 struct if_stats_msg *ifsm = NLMSG_DATA(n);
1343 struct rtattr *tb[IFLA_STATS_MAX+1];
1344 int len = n->nlmsg_len;
1345 struct af_stats_ctx *ctx = arg;
1346 FILE *fp = ctx->fp;
1347
1348 len -= NLMSG_LENGTH(sizeof(*ifsm));
1349 if (len < 0) {
1350 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
1351 return -1;
1352 }
1353
1354 if (ctx->ifindex && ifsm->ifindex != ctx->ifindex)
1355 return 0;
1356
1357 parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
1358
1359 if (tb[IFLA_STATS_AF_SPEC])
1360 print_af_stats_attr(fp, ifsm->ifindex, tb[IFLA_STATS_AF_SPEC]);
1361
1362 fflush(fp);
1363 return 0;
1364}
1365
1366static int iplink_afstats(int argc, char **argv)
1367{
1368 __u32 filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_AF_SPEC);
1369 const char *filter_dev = NULL;
1370 struct af_stats_ctx ctx = {
1371 .fp = stdout,
1372 .ifindex = 0,
1373 };
1374
1375 while (argc > 0) {
1376 if (strcmp(*argv, "dev") == 0) {
1377 NEXT_ARG();
1378 if (filter_dev)
1379 duparg2("dev", *argv);
1380 filter_dev = *argv;
1381 } else if (matches(*argv, "help") == 0) {
1382 usage();
1383 } else {
1384 fprintf(stderr,
1385 "Command \"%s\" is unknown, try \"ip link help\".\n",
1386 *argv);
1387 exit(-1);
1388 }
1389
1390 argv++; argc--;
1391 }
1392
1393 if (filter_dev) {
1394 ctx.ifindex = ll_name_to_index(filter_dev);
1395 if (ctx.ifindex <= 0) {
1396 fprintf(stderr,
1397 "Device \"%s\" does not exist.\n",
1398 filter_dev);
1399 return -1;
1400 }
1401 }
1402
1403 new_json_obj(json);
1404
1405 if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
1406 NULL, NULL) < 0) {
1407 perror("Cannot send dump request");
1408 delete_json_obj();
1409 return 1;
1410 }
1411
1412 if (rtnl_dump_filter(&rth, print_af_stats, &ctx) < 0) {
1413 fprintf(stderr, "Dump terminated\n");
1414 delete_json_obj();
1415 return 1;
1416 }
1417
1418 delete_json_obj();
1419 return 0;
1420}
1421
1422static int iplink_prop_mod(int argc, char **argv, struct iplink_req *req)
1423{
1424 struct rtattr *proplist;
1425 char *dev = NULL;
1426 char *name;
1427
1428 proplist = addattr_nest(&req->n, sizeof(*req),
1429 IFLA_PROP_LIST | NLA_F_NESTED);
1430
1431 while (argc > 0) {
1432 if (matches(*argv, "altname") == 0) {
1433 NEXT_ARG();
1434 if (check_altifname(*argv))
1435 invarg("not a valid altname", *argv);
1436 name = *argv;
1437 addattr_l(&req->n, sizeof(*req), IFLA_ALT_IFNAME,
1438 name, strlen(name) + 1);
1439 } else if (matches(*argv, "help") == 0) {
1440 usage();
1441 } else {
1442 if (strcmp(*argv, "dev") == 0)
1443 NEXT_ARG();
1444 if (dev)
1445 duparg2("dev", *argv);
1446 if (check_altifname(*argv))
1447 invarg("\"dev\" not a valid ifname", *argv);
1448 dev = *argv;
1449 }
1450 argv++; argc--;
1451 }
1452 addattr_nest_end(&req->n, proplist);
1453
1454 if (!dev) {
1455 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
1456 exit(-1);
1457 }
1458
1459 req->i.ifi_index = ll_name_to_index(dev);
1460 if (!req->i.ifi_index)
1461 return nodev(dev);
1462
1463 if (rtnl_talk(&rth, &req->n, NULL) < 0)
1464 return -2;
1465
1466 return 0;
1467}
1468
1469static int iplink_prop(int argc, char **argv)
1470{
1471 struct iplink_req req = {
1472 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
1473 .n.nlmsg_flags = NLM_F_REQUEST,
1474 .i.ifi_family = preferred_family,
1475 };
1476
1477 if (argc <= 0) {
1478 usage();
1479 exit(-1);
1480 }
1481
1482 if (matches(*argv, "add") == 0) {
1483 req.n.nlmsg_flags |= NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND;
1484 req.n.nlmsg_type = RTM_NEWLINKPROP;
1485 } else if (matches(*argv, "del") == 0) {
1486 req.n.nlmsg_type = RTM_DELLINKPROP;
1487 } else if (matches(*argv, "help") == 0) {
1488 usage();
1489 } else {
1490 fprintf(stderr, "Operator required\n");
1491 exit(-1);
1492 }
1493 return iplink_prop_mod(argc - 1, argv + 1, &req);
1494}
1495
1496static void do_help(int argc, char **argv)
1497{
1498 struct link_util *lu = NULL;
1499
1500 if (argc <= 0) {
1501 usage();
1502 return;
1503 }
1504
1505 lu = get_link_kind(*argv);
1506 if (lu && lu->print_help)
1507 lu->print_help(lu, argc-1, argv+1, stdout);
1508 else
1509 usage();
1510}
1511
1512int do_iplink(int argc, char **argv)
1513{
1514 if (argc < 1)
1515 return ipaddr_list_link(0, NULL);
1516
1517 if (matches(*argv, "add") == 0)
1518 return iplink_modify(RTM_NEWLINK,
1519 NLM_F_CREATE|NLM_F_EXCL,
1520 argc-1, argv+1);
1521 if (matches(*argv, "set") == 0 ||
1522 matches(*argv, "change") == 0)
1523 return iplink_modify(RTM_NEWLINK, 0,
1524 argc-1, argv+1);
1525 if (matches(*argv, "replace") == 0)
1526 return iplink_modify(RTM_NEWLINK,
1527 NLM_F_CREATE|NLM_F_REPLACE,
1528 argc-1, argv+1);
1529 if (matches(*argv, "delete") == 0)
1530 return iplink_modify(RTM_DELLINK, 0,
1531 argc-1, argv+1);
1532 if (matches(*argv, "show") == 0 ||
1533 matches(*argv, "lst") == 0 ||
1534 matches(*argv, "list") == 0)
1535 return ipaddr_list_link(argc-1, argv+1);
1536
1537 if (matches(*argv, "xstats") == 0)
1538 return iplink_ifla_xstats(argc-1, argv+1);
1539
1540 if (matches(*argv, "afstats") == 0) {
1541 iplink_afstats(argc-1, argv+1);
1542 return 0;
1543 }
1544
1545 if (matches(*argv, "property") == 0)
1546 return iplink_prop(argc-1, argv+1);
1547
1548 if (matches(*argv, "help") == 0) {
1549 do_help(argc-1, argv+1);
1550 return 0;
1551 }
1552
1553 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n",
1554 *argv);
1555 exit(-1);
1556}
1557