chiark / gitweb /
9716499a7393515c54d81c33a593990eb89608a7
[elogind.git] / src / network / networkctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdbool.h>
23 #include <getopt.h>
24 #include <net/if.h>
25
26 #include "sd-network.h"
27 #include "sd-rtnl.h"
28 #include "sd-hwdb.h"
29 #include "sd-device.h"
30
31 #include "strv.h"
32 #include "build.h"
33 #include "util.h"
34 #include "pager.h"
35 #include "lldp.h"
36 #include "rtnl-util.h"
37 #include "device-util.h"
38 #include "hwdb-util.h"
39 #include "arphrd-list.h"
40 #include "local-addresses.h"
41 #include "socket-util.h"
42 #include "ether-addr-util.h"
43 #include "verbs.h"
44
45 static bool arg_no_pager = false;
46 static bool arg_legend = true;
47 static bool arg_all = false;
48
49 static void pager_open_if_enabled(void) {
50
51         if (arg_no_pager)
52                 return;
53
54         pager_open(false);
55 }
56
57 static int link_get_type_string(int iftype, sd_device *d, char **ret) {
58         const char *t;
59         char *p;
60
61         assert(ret);
62
63         if (iftype == ARPHRD_ETHER && d) {
64                 const char *devtype, *id = NULL;
65                 /* WLANs have iftype ARPHRD_ETHER, but we want
66                  * to show a more useful type string for
67                  * them */
68
69                 (void)sd_device_get_devtype(d, &devtype);
70
71                 if (streq_ptr(devtype, "wlan"))
72                         id = "wlan";
73                 else if (streq_ptr(devtype, "wwan"))
74                         id = "wwan";
75
76                 if (id) {
77                         p = strdup(id);
78                         if (!p)
79                                 return -ENOMEM;
80
81                         *ret = p;
82                         return 1;
83                 }
84         }
85
86         t = arphrd_to_name(iftype);
87         if (!t) {
88                 *ret = NULL;
89                 return 0;
90         }
91
92         p = strdup(t);
93         if (!p)
94                 return -ENOMEM;
95
96         ascii_strlower(p);
97         *ret = p;
98
99         return 0;
100 }
101
102 typedef struct LinkInfo {
103         const char *name;
104         int ifindex;
105         unsigned iftype;
106 } LinkInfo;
107
108 static int link_info_compare(const void *a, const void *b) {
109         const LinkInfo *x = a, *y = b;
110
111         return x->ifindex - y->ifindex;
112 }
113
114 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
115         _cleanup_free_ LinkInfo *links = NULL;
116         size_t size = 0, c = 0;
117         sd_rtnl_message *i;
118         int r;
119
120         for (i = m; i; i = sd_rtnl_message_next(i)) {
121                 const char *name;
122                 unsigned iftype;
123                 uint16_t type;
124                 int ifindex;
125
126                 r = sd_rtnl_message_get_type(i, &type);
127                 if (r < 0)
128                         return r;
129
130                 if (type != RTM_NEWLINK)
131                         continue;
132
133                 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
134                 if (r < 0)
135                         return r;
136
137                 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
138                 if (r < 0)
139                         return r;
140
141                 r = sd_rtnl_message_link_get_type(i, &iftype);
142                 if (r < 0)
143                         return r;
144
145                 if (!GREEDY_REALLOC(links, size, c+1))
146                         return -ENOMEM;
147
148                 links[c].name = name;
149                 links[c].ifindex = ifindex;
150                 links[c].iftype = iftype;
151                 c++;
152         }
153
154         qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
155
156         *ret = links;
157         links = NULL;
158
159         return (int) c;
160 }
161
162 static void operational_state_to_color(const char *state, const char **on, const char **off) {
163         assert(on);
164         assert(off);
165
166         if (streq_ptr(state, "routable")) {
167                 *on = ansi_highlight_green();
168                 *off = ansi_highlight_off();
169         } else if (streq_ptr(state, "degraded")) {
170                 *on = ansi_highlight_yellow();
171                 *off = ansi_highlight_off();
172         } else
173                 *on = *off = "";
174 }
175
176 static void setup_state_to_color(const char *state, const char **on, const char **off) {
177         assert(on);
178         assert(off);
179
180         if (streq_ptr(state, "configured")) {
181                 *on = ansi_highlight_green();
182                 *off = ansi_highlight_off();
183         } else if (streq_ptr(state, "configuring")) {
184                 *on = ansi_highlight_yellow();
185                 *off = ansi_highlight_off();
186         } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
187                 *on = ansi_highlight_red();
188                 *off = ansi_highlight_off();
189         } else
190                 *on = *off = "";
191 }
192
193 static int list_links(int argc, char *argv[], void *userdata) {
194         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
195         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
196         _cleanup_free_ LinkInfo *links = NULL;
197         int r, c, i;
198
199         pager_open_if_enabled();
200
201         r = sd_rtnl_open(&rtnl, 0);
202         if (r < 0)
203                 return log_error_errno(r, "Failed to connect to netlink: %m");
204
205         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
206         if (r < 0)
207                 return rtnl_log_create_error(r);
208
209         r = sd_rtnl_message_request_dump(req, true);
210         if (r < 0)
211                 return rtnl_log_create_error(r);
212
213         r = sd_rtnl_call(rtnl, req, 0, &reply);
214         if (r < 0)
215                 return log_error_errno(r, "Failed to enumerate links: %m");
216
217         if (arg_legend)
218                 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
219
220         c = decode_and_sort_links(reply, &links);
221         if (c < 0)
222                 return rtnl_log_parse_error(c);
223
224         for (i = 0; i < c; i++) {
225                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
226                 _cleanup_device_unref_ sd_device *d = NULL;
227                 const char *on_color_operational, *off_color_operational,
228                            *on_color_setup, *off_color_setup;
229                  char devid[2 + DECIMAL_STR_MAX(int)];
230                 _cleanup_free_ char *t = NULL;
231
232                 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
233                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
234
235                 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
236                 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
237
238                 sprintf(devid, "n%i", links[i].ifindex);
239                 (void)sd_device_new_from_device_id(&d, devid);
240
241                 link_get_type_string(links[i].iftype, d, &t);
242
243                 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
244                        links[i].ifindex, links[i].name, strna(t),
245                        on_color_operational, strna(operational_state), off_color_operational,
246                        on_color_setup, strna(setup_state), off_color_setup);
247         }
248
249         if (arg_legend)
250                 printf("\n%i links listed.\n", c);
251
252         return 0;
253 }
254
255 /* IEEE Organizationally Unique Identifier vendor string */
256 static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
257         const char *description;
258         char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
259         int r;
260
261         assert(ret);
262
263         if (!hwdb)
264                 return -EINVAL;
265
266         if (!mac)
267                 return -EINVAL;
268
269         /* skip commonly misused 00:00:00 (Xerox) prefix */
270         if (memcmp(mac, "\0\0\0", 3) == 0)
271                 return -EINVAL;
272
273         snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
274
275         r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
276         if (r < 0)
277                 return r;
278
279         desc = strdup(description);
280         if (!desc)
281                 return -ENOMEM;
282
283         *ret = desc;
284
285         return 0;
286 }
287
288 static int get_gateway_description(
289                 sd_rtnl *rtnl,
290                 sd_hwdb *hwdb,
291                 int ifindex,
292                 int family,
293                 union in_addr_union *gateway,
294                 char **gateway_description) {
295         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
296         sd_rtnl_message *m;
297         int r;
298
299         assert(rtnl);
300         assert(ifindex >= 0);
301         assert(family == AF_INET || family == AF_INET6);
302         assert(gateway);
303         assert(gateway_description);
304
305         r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
306         if (r < 0)
307                 return r;
308
309         r = sd_rtnl_message_request_dump(req, true);
310         if (r < 0)
311                 return r;
312
313         r = sd_rtnl_call(rtnl, req, 0, &reply);
314         if (r < 0)
315                 return r;
316
317         for (m = reply; m; m = sd_rtnl_message_next(m)) {
318                 union in_addr_union gw = {};
319                 struct ether_addr mac = {};
320                 uint16_t type;
321                 int ifi, fam;
322
323                 r = sd_rtnl_message_get_errno(m);
324                 if (r < 0) {
325                         log_error_errno(r, "got error: %m");
326                         continue;
327                 }
328
329                 r = sd_rtnl_message_get_type(m, &type);
330                 if (r < 0) {
331                         log_error_errno(r, "could not get type: %m");
332                         continue;
333                 }
334
335                 if (type != RTM_NEWNEIGH) {
336                         log_error("type is not RTM_NEWNEIGH");
337                         continue;
338                 }
339
340                 r = sd_rtnl_message_neigh_get_family(m, &fam);
341                 if (r < 0) {
342                         log_error_errno(r, "could not get family: %m");
343                         continue;
344                 }
345
346                 if (fam != family) {
347                         log_error("family is not correct");
348                         continue;
349                 }
350
351                 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
352                 if (r < 0) {
353                         log_error_errno(r, "could not get ifindex: %m");
354                         continue;
355                 }
356
357                 if (ifindex > 0 && ifi != ifindex)
358                         continue;
359
360                 switch (fam) {
361                 case AF_INET:
362                         r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
363                         if (r < 0)
364                                 continue;
365
366                         break;
367                 case AF_INET6:
368                         r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
369                         if (r < 0)
370                                 continue;
371
372                         break;
373                 default:
374                         continue;
375                 }
376
377                 if (!in_addr_equal(fam, &gw, gateway))
378                         continue;
379
380                 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
381                 if (r < 0)
382                         continue;
383
384                 r = ieee_oui(hwdb, &mac, gateway_description);
385                 if (r < 0)
386                         continue;
387
388                 return 0;
389         }
390
391         return -ENODATA;
392 }
393
394 static int dump_gateways(
395                 sd_rtnl *rtnl,
396                 sd_hwdb *hwdb,
397                 const char *prefix,
398                 int ifindex) {
399         _cleanup_free_ struct local_address *local = NULL;
400         int r, n, i;
401
402         n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
403         if (n < 0)
404                 return n;
405
406         for (i = 0; i < n; i++) {
407                 _cleanup_free_ char *gateway = NULL, *description = NULL;
408
409                 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
410                 if (r < 0)
411                         return r;
412
413                 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
414                 if (r < 0)
415                         log_debug_errno(r, "Could not get description of gateway: %m");
416
417                 printf("%*s%s",
418                        (int) strlen(prefix),
419                        i == 0 ? prefix : "",
420                        gateway);
421
422                 if (description)
423                         printf(" (%s)", description);
424
425                 /* Show interface name for the entry if we show
426                  * entries for all interfaces */
427                 if (ifindex <= 0) {
428                         char name[IF_NAMESIZE+1];
429
430                         if (if_indextoname(local[i].ifindex, name)) {
431                                 fputs(" on ", stdout);
432                                 fputs(name, stdout);
433                         } else
434                                 printf(" on %%%i", local[i].ifindex);
435                 }
436
437                 fputc('\n', stdout);
438         }
439
440         return 0;
441 }
442
443 static int dump_addresses(
444                 sd_rtnl *rtnl,
445                 const char *prefix,
446                 int ifindex) {
447
448         _cleanup_free_ struct local_address *local = NULL;
449         int r, n, i;
450
451         n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
452         if (n < 0)
453                 return n;
454
455         for (i = 0; i < n; i++) {
456                 _cleanup_free_ char *pretty = NULL;
457
458                 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
459                 if (r < 0)
460                         return r;
461
462                 printf("%*s%s",
463                        (int) strlen(prefix),
464                        i == 0 ? prefix : "",
465                        pretty);
466
467                 if (ifindex <= 0) {
468                         char name[IF_NAMESIZE+1];
469
470                         if (if_indextoname(local[i].ifindex, name)) {
471                                 fputs(" on ", stdout);
472                                 fputs(name, stdout);
473                         } else
474                                 printf(" on %%%i", local[i].ifindex);
475                 }
476
477                 fputc('\n', stdout);
478         }
479
480         return 0;
481 }
482
483 static void dump_list(const char *prefix, char **l) {
484         char **i;
485
486         STRV_FOREACH(i, l) {
487                 printf("%*s%s\n",
488                        (int) strlen(prefix),
489                        i == l ? prefix : "",
490                        *i);
491         }
492 }
493
494 static int link_status_one(
495                 sd_rtnl *rtnl,
496                 sd_hwdb *hwdb,
497                 const char *name) {
498         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
499         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
500         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
501         _cleanup_device_unref_ sd_device *d = NULL;
502         char devid[2 + DECIMAL_STR_MAX(int)];
503         _cleanup_free_ char *t = NULL, *network = NULL;
504         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
505         const char *on_color_operational, *off_color_operational,
506                    *on_color_setup, *off_color_setup;
507         _cleanup_strv_free_ char **carrier_bound_to = NULL;
508         _cleanup_strv_free_ char **carrier_bound_by = NULL;
509         struct ether_addr e;
510         unsigned iftype;
511         int r, ifindex;
512         bool have_mac;
513         uint32_t mtu;
514
515         assert(rtnl);
516         assert(name);
517
518         if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
519                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
520         else {
521                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
522                 if (r < 0)
523                         return rtnl_log_create_error(r);
524
525                 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
526         }
527
528         if (r < 0)
529                 return rtnl_log_create_error(r);
530
531         r = sd_rtnl_call(rtnl, req, 0, &reply);
532         if (r < 0)
533                 return log_error_errno(r, "Failed to query link: %m");
534
535         r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
536         if (r < 0)
537                 return rtnl_log_parse_error(r);
538
539         r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
540         if (r < 0)
541                 return rtnl_log_parse_error(r);
542
543         r = sd_rtnl_message_link_get_type(reply, &iftype);
544         if (r < 0)
545                 return rtnl_log_parse_error(r);
546
547         have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
548
549         if (have_mac) {
550                 const uint8_t *p;
551                 bool all_zeroes = true;
552
553                 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
554                         if (*p != 0) {
555                                 all_zeroes = false;
556                                 break;
557                         }
558
559                 if (all_zeroes)
560                         have_mac = false;
561         }
562
563         sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
564
565         sd_network_link_get_operational_state(ifindex, &operational_state);
566         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
567
568         sd_network_link_get_setup_state(ifindex, &setup_state);
569         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
570
571         sd_network_link_get_dns(ifindex, &dns);
572         sd_network_link_get_ntp(ifindex, &ntp);
573         sd_network_link_get_domains(ifindex, &domains);
574         r = sd_network_link_get_wildcard_domain(ifindex);
575         if (r > 0) {
576                 char *wildcard;
577
578                 wildcard = strdup("*");
579                 if (!wildcard)
580                         return log_oom();
581
582                 if (strv_consume(&domains, wildcard) < 0)
583                         return log_oom();
584         }
585
586         sprintf(devid, "n%i", ifindex);
587
588         (void)sd_device_new_from_device_id(&d, devid);
589
590         if (d) {
591                 (void)sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
592                 (void)sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
593                 (void)sd_device_get_property_value(d, "ID_PATH", &path);
594
595                 r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor);
596                 if (r < 0)
597                         (void)sd_device_get_property_value(d, "ID_VENDOR", &vendor);
598
599                 r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model);
600                 if (r < 0)
601                         (void)sd_device_get_property_value(d, "ID_MODEL", &model);
602         }
603
604         link_get_type_string(iftype, d, &t);
605
606         sd_network_link_get_network_file(ifindex, &network);
607
608         sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to);
609         sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by);
610
611         printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
612
613         printf("       Link File: %s\n"
614                "    Network File: %s\n"
615                "            Type: %s\n"
616                "           State: %s%s%s (%s%s%s)\n",
617                strna(link),
618                strna(network),
619                strna(t),
620                on_color_operational, strna(operational_state), off_color_operational,
621                on_color_setup, strna(setup_state), off_color_setup);
622
623         if (path)
624                 printf("            Path: %s\n", path);
625         if (driver)
626                 printf("          Driver: %s\n", driver);
627         if (vendor)
628                 printf("          Vendor: %s\n", vendor);
629         if (model)
630                 printf("           Model: %s\n", model);
631
632         if (have_mac) {
633                 _cleanup_free_ char *description = NULL;
634                 char ea[ETHER_ADDR_TO_STRING_MAX];
635
636                 ieee_oui(hwdb, &e, &description);
637
638                 if (description)
639                         printf("      HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
640                 else
641                         printf("      HW Address: %s\n", ether_addr_to_string(&e, ea));
642         }
643
644         if (mtu > 0)
645                 printf("             MTU: %u\n", mtu);
646
647         dump_addresses(rtnl, "         Address: ", ifindex);
648         dump_gateways(rtnl, hwdb, "         Gateway: ", ifindex);
649
650         if (!strv_isempty(dns))
651                 dump_list("             DNS: ", dns);
652         if (!strv_isempty(domains))
653                 dump_list("          Domain: ", domains);
654         if (!strv_isempty(ntp))
655                 dump_list("             NTP: ", ntp);
656
657         if (!strv_isempty(carrier_bound_to))
658                 dump_list("Carrier Bound To: ", carrier_bound_to);
659
660         if (!strv_isempty(carrier_bound_by))
661                 dump_list("Carrier Bound By: ", carrier_bound_by);
662
663         return 0;
664 }
665
666 static int link_status(int argc, char *argv[], void *userdata) {
667         _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
668         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
669         char **name;
670         int r;
671
672         r = sd_rtnl_open(&rtnl, 0);
673         if (r < 0)
674                 return log_error_errno(r, "Failed to connect to netlink: %m");
675
676         r = sd_hwdb_new(&hwdb);
677         if (r < 0)
678                 log_debug_errno(r, "Failed to open hardware database: %m");
679
680         if (argc <= 1 && !arg_all) {
681                 _cleanup_free_ char *operational_state = NULL;
682                 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
683                 const char *on_color_operational, *off_color_operational;
684
685                 sd_network_get_operational_state(&operational_state);
686                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
687
688                 printf("%s%s%s      State: %s%s%s\n",
689                        on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
690                        on_color_operational, strna(operational_state), off_color_operational);
691
692                 dump_addresses(rtnl, "     Address: ", 0);
693                 dump_gateways(rtnl, hwdb, "     Gateway: ", 0);
694
695                 sd_network_get_dns(&dns);
696                 if (!strv_isempty(dns))
697                         dump_list("         DNS: ", dns);
698
699                 sd_network_get_domains(&domains);
700                 if (!strv_isempty(domains))
701                         dump_list("      Domain: ", domains);
702
703                 sd_network_get_ntp(&ntp);
704                 if (!strv_isempty(ntp))
705                         dump_list("         NTP: ", ntp);
706
707                 return 0;
708         }
709
710         pager_open_if_enabled();
711
712         if (arg_all) {
713                 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
714                 _cleanup_free_ LinkInfo *links = NULL;
715                 int c, i;
716
717                 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
718                 if (r < 0)
719                         return rtnl_log_create_error(r);
720
721                 r = sd_rtnl_message_request_dump(req, true);
722                 if (r < 0)
723                         return rtnl_log_create_error(r);
724
725                 r = sd_rtnl_call(rtnl, req, 0, &reply);
726                 if (r < 0)
727                         return log_error_errno(r, "Failed to enumerate links: %m");
728
729                 c = decode_and_sort_links(reply, &links);
730                 if (c < 0)
731                         return rtnl_log_parse_error(c);
732
733                 for (i = 0; i < c; i++) {
734                         if (i > 0)
735                                 fputc('\n', stdout);
736
737                         link_status_one(rtnl, hwdb, links[i].name);
738                 }
739         } else {
740                 STRV_FOREACH(name, argv + 1) {
741                         if (name != argv + 1)
742                                 fputc('\n', stdout);
743
744                         link_status_one(rtnl, hwdb, *name);
745                 }
746         }
747
748         return 0;
749 }
750
751 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
752 LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
753
754 static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
755         [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
756         [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
757         [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
758         [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
759         [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
760         [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
761         [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
762         [LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
763         [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
764         [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
765         [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
766         [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
767 };
768
769 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
770
771 static char *lldp_system_caps(uint16_t cap) {
772         _cleanup_free_ char *s = NULL, *t = NULL;
773         char *capability;
774
775         t = strdup("[ ");
776         if (!t)
777                 return NULL;
778
779         if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
780                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
781                 if (!s)
782                         return NULL;
783
784                 free(t);
785                 t = s;
786         }
787
788         if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
789                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
790                 if (!s)
791                         return NULL;
792
793                 free(t);
794                 t = s;
795         }
796
797         if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
798                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
799                 if (!s)
800                         return NULL;
801
802                 free(t);
803                 t = s;
804         }
805
806         if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
807                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
808                 if (!s)
809                         return NULL;
810
811                 free(t);
812                 t = s;
813         }
814
815         if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
816                 s =  strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
817                 if (!s)
818                         return NULL;
819
820                 free(t);
821                 t = s;
822         }
823
824         if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
825                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
826                 if (!s)
827                         return NULL;
828
829                 free(t);
830                 t = s;
831         }
832
833         if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
834                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
835                 if (!s)
836                         return NULL;
837
838                 free(t);
839                 t = s;
840         }
841
842         if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
843                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
844                 if (!s)
845                         return NULL;
846
847                 free(t);
848                 t = s;
849         }
850
851         if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
852                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
853                 if (!s)
854                         return NULL;
855
856                 free(t);
857                 t = s;
858         }
859
860         if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
861                 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
862                 if (!s)
863                         return NULL;
864
865                 free(t);
866                 t = s;
867         }
868
869         if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
870                 s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
871                 if (!s)
872                         return NULL;
873
874                 free(t);
875         }
876
877         if (!s) {
878                 s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
879                 if (!s)
880                         return NULL;
881
882                 free(t);
883         }
884
885         t = strappend(s, "]");
886         if (!t)
887                 return NULL;
888
889         free(s);
890         capability = t;
891
892         s = NULL;
893         t = NULL;
894
895         return capability;
896 }
897
898 static int link_lldp_status(int argc, char *argv[], void *userdata) {
899         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
900         _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
901         _cleanup_free_ LinkInfo *links = NULL;
902         const char *state, *word;
903
904         double ttl = -1;
905         uint32_t capability;
906         int i, r, c, j;
907         size_t ll;
908         char **s;
909
910         pager_open_if_enabled();
911
912         r = sd_rtnl_open(&rtnl, 0);
913         if (r < 0)
914                 return log_error_errno(r, "Failed to connect to netlink: %m");
915
916         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
917         if (r < 0)
918                 return rtnl_log_create_error(r);
919
920         r = sd_rtnl_message_request_dump(req, true);
921         if (r < 0)
922                 return rtnl_log_create_error(r);
923
924         r = sd_rtnl_call(rtnl, req, 0, &reply);
925         if (r < 0)
926                 return log_error_errno(r, "Failed to enumerate links: %m");
927
928         c = decode_and_sort_links(reply, &links);
929         if (c < 0)
930                 return rtnl_log_parse_error(c);
931
932         if (arg_legend)
933                 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
934
935         for (i = j = 0; i < c; i++) {
936                 _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
937                 _cleanup_strv_free_ char **l = NULL;
938
939                 r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
940                 if (r < 0)
941                         continue;
942
943                 l = strv_split_newlines(lldp);
944                 if (!l)
945                         return -ENOMEM;
946
947                 STRV_FOREACH(s, l) {
948                         FOREACH_WORD_QUOTED(word, ll, *s, state) {
949                                 _cleanup_free_ char *t = NULL, *a = NULL, *b = NULL;
950
951                                 t = strndup(word, ll);
952                                 if (!t)
953                                         return -ENOMEM;
954
955                                 r = split_pair(t, "=", &a, &b);
956                                 if (r < 0)
957                                         continue;
958
959                                 if (streq(a, "_Chassis")) {
960                                         r = free_and_strdup(&chassis, b);
961                                         if (r < 0)
962                                                 return r;
963
964                                 } else if (streq(a, "_Port")) {
965                                         r = free_and_strdup(&port, b);
966                                         if (r < 0)
967                                                 return r;
968
969                                 } else if (streq(a, "_TTL")) {
970                                         long long unsigned x = 0;
971                                         usec_t time;
972
973                                         r = safe_atollu(b, &x);
974                                         if (r < 0 || (usec_t) x != x)
975                                                 return log_warning_errno(r < 0 ? r : ERANGE,
976                                                                          "Failed to parse TTL \"%s\": %m", b);
977
978                                         time = now(CLOCK_BOOTTIME);
979                                         if (x < time)
980                                                 continue;
981
982                                         ttl = (double) (x - time) / USEC_PER_SEC;
983
984                                 } else if (streq(a, "_CAP")) {
985                                         sscanf(b, "%x", &capability);
986
987                                         cap = lldp_system_caps(capability);
988                                 }
989
990                         }
991
992                         if (ttl >= 0) {
993                                 printf("%10s %24s %16s %16f %16s\n",
994                                        links[i].name,
995                                        strna(chassis), strna(port),
996                                        ttl, cap);
997                                 j++;
998                         }
999                 }
1000         }
1001
1002         if (arg_legend) {
1003                 printf("\nCapability Codes:\n"
1004                        "(O) - Other, (P) - Repeater,  (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1005                        "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1006                        "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1007
1008                 printf("Total entries displayed: %d\n", j);
1009         }
1010
1011         return 0;
1012 }
1013
1014 static void help(void) {
1015         printf("%s [OPTIONS...]\n\n"
1016                "Query and control the networking subsystem.\n\n"
1017                "  -h --help             Show this help\n"
1018                "     --version          Show package version\n"
1019                "     --no-pager         Do not pipe output into a pager\n"
1020                "     --no-legend        Do not show the headers and footers\n"
1021                "  -a --all              Show status for all links\n\n"
1022                "Commands:\n"
1023                "  list                  List links\n"
1024                "  status [LINK...]      Show link status\n"
1025                "  lldp                  Show lldp information\n"
1026                , program_invocation_short_name);
1027 }
1028
1029 static int parse_argv(int argc, char *argv[]) {
1030
1031         enum {
1032                 ARG_VERSION = 0x100,
1033                 ARG_NO_PAGER,
1034                 ARG_NO_LEGEND,
1035         };
1036
1037         static const struct option options[] = {
1038                 { "help",      no_argument,       NULL, 'h'           },
1039                 { "version",   no_argument,       NULL, ARG_VERSION   },
1040                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
1041                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
1042                 { "all",       no_argument,       NULL, 'a'           },
1043                 {}
1044         };
1045
1046         int c;
1047
1048         assert(argc >= 0);
1049         assert(argv);
1050
1051         while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
1052
1053                 switch (c) {
1054
1055                 case 'h':
1056                         help();
1057                         return 0;
1058
1059                 case ARG_VERSION:
1060                         puts(PACKAGE_STRING);
1061                         puts(SYSTEMD_FEATURES);
1062                         return 0;
1063
1064                 case ARG_NO_PAGER:
1065                         arg_no_pager = true;
1066                         break;
1067
1068                 case ARG_NO_LEGEND:
1069                         arg_legend = false;
1070                         break;
1071
1072                 case 'a':
1073                         arg_all = true;
1074                         break;
1075
1076                 case '?':
1077                         return -EINVAL;
1078
1079                 default:
1080                         assert_not_reached("Unhandled option");
1081                 }
1082         }
1083
1084         return 1;
1085 }
1086
1087 static int networkctl_main(int argc, char *argv[]) {
1088         const Verb verbs[] = {
1089                 { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
1090                 { "status", 1, VERB_ANY, 0, link_status },
1091                 { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
1092                 {}
1093         };
1094
1095         return dispatch_verb(argc, argv, verbs, NULL);
1096 }
1097
1098 int main(int argc, char* argv[]) {
1099         int r;
1100
1101         log_parse_environment();
1102         log_open();
1103
1104         r = parse_argv(argc, argv);
1105         if (r <= 0)
1106                 goto finish;
1107
1108         r = networkctl_main(argc, argv);
1109
1110 finish:
1111         pager_close();
1112
1113         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1114 }