2017-11-18 17:09:20 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
#include <getopt.h>
|
2017-06-26 19:58:10 +02:00
|
|
|
#include <linux/if_addrlabel.h>
|
2014-12-12 19:07:26 +01:00
|
|
|
#include <net/if.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <stdbool.h>
|
2019-03-27 11:32:41 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2020-03-22 14:27:30 +01:00
|
|
|
#include <linux/if_bridge.h>
|
2020-03-17 06:08:05 +01:00
|
|
|
#include <linux/if_tunnel.h>
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
#include "sd-bus.h"
|
2014-12-05 01:16:05 +01:00
|
|
|
#include "sd-device.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "sd-hwdb.h"
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
#include "sd-lldp.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "sd-netlink.h"
|
|
|
|
#include "sd-network.h"
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2019-05-25 17:22:05 +02:00
|
|
|
#include "bus-common-errors.h"
|
|
|
|
#include "bus-error.h"
|
|
|
|
#include "bus-util.h"
|
2020-03-24 12:23:35 +01:00
|
|
|
#include "bridge-util.h"
|
2014-12-05 01:16:05 +01:00
|
|
|
#include "device-util.h"
|
2019-10-23 17:05:33 +02:00
|
|
|
#include "escape.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "ether-addr-util.h"
|
2019-06-17 09:12:06 +02:00
|
|
|
#include "ethtool-util.h"
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
#include "fd-util.h"
|
2019-05-22 19:21:17 +02:00
|
|
|
#include "format-table.h"
|
2019-05-29 07:18:41 +02:00
|
|
|
#include "format-util.h"
|
2020-03-25 14:52:52 +01:00
|
|
|
#include "geneve-util.h"
|
2020-01-12 12:14:31 +01:00
|
|
|
#include "glob-util.h"
|
2014-12-15 20:07:34 +01:00
|
|
|
#include "hwdb-util.h"
|
2014-08-12 01:41:42 +02:00
|
|
|
#include "local-addresses.h"
|
2015-10-26 23:01:30 +01:00
|
|
|
#include "locale-util.h"
|
2020-01-07 03:32:03 +01:00
|
|
|
#include "logs-show.h"
|
2017-06-26 19:58:10 +02:00
|
|
|
#include "macro.h"
|
2020-03-19 05:24:49 +01:00
|
|
|
#include "macvlan-util.h"
|
2018-11-20 09:57:30 +01:00
|
|
|
#include "main-func.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "netlink-util.h"
|
2020-02-27 13:56:36 +01:00
|
|
|
#include "network-internal.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "pager.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2018-11-20 15:42:57 +01:00
|
|
|
#include "pretty-print.h"
|
2019-05-22 11:46:41 +02:00
|
|
|
#include "set.h"
|
2020-01-11 11:21:01 +01:00
|
|
|
#include "socket-netlink.h"
|
2014-08-15 13:18:50 +02:00
|
|
|
#include "socket-util.h"
|
2019-03-13 12:14:47 +01:00
|
|
|
#include "sort-util.h"
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
#include "sparse-endian.h"
|
2016-01-12 15:34:20 +01:00
|
|
|
#include "stdio-util.h"
|
2015-10-26 22:31:05 +01:00
|
|
|
#include "string-table.h"
|
2015-10-26 23:01:30 +01:00
|
|
|
#include "string-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "strv.h"
|
2016-03-02 21:43:41 +01:00
|
|
|
#include "strxcpyx.h"
|
2015-04-10 23:15:59 +02:00
|
|
|
#include "terminal-util.h"
|
2020-01-07 03:32:03 +01:00
|
|
|
#include "unit-def.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "verbs.h"
|
2019-10-23 17:05:33 +02:00
|
|
|
#include "wifi-util.h"
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
/* Kernel defines MODULE_NAME_LEN as 64 - sizeof(unsigned long). So, 64 is enough. */
|
|
|
|
#define NETDEV_KIND_MAX 64
|
|
|
|
|
2019-10-23 17:05:33 +02:00
|
|
|
/* use 128 kB for receive socket kernel queue, we shouldn't need more here */
|
|
|
|
#define RCVBUF_SIZE (128*1024)
|
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
static PagerFlags arg_pager_flags = 0;
|
2014-08-12 01:41:42 +02:00
|
|
|
static bool arg_legend = true;
|
2014-08-12 15:19:30 +02:00
|
|
|
static bool arg_all = false;
|
2019-05-24 17:37:48 +02:00
|
|
|
static bool arg_stats = false;
|
2020-01-07 03:32:03 +01:00
|
|
|
static bool arg_full = false;
|
|
|
|
static unsigned arg_lines = 10;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2019-10-23 11:10:32 +02:00
|
|
|
static void operational_state_to_color(const char *name, const char *state, const char **on, const char **off) {
|
2016-02-19 19:21:30 +01:00
|
|
|
assert(on);
|
|
|
|
assert(off);
|
|
|
|
|
2019-10-23 11:10:32 +02:00
|
|
|
if (STRPTR_IN_SET(state, "routable", "enslaved") ||
|
|
|
|
(streq_ptr(name, "lo") && streq_ptr(state, "carrier"))) {
|
2016-02-19 19:21:30 +01:00
|
|
|
*on = ansi_highlight_green();
|
|
|
|
*off = ansi_normal();
|
|
|
|
} else if (streq_ptr(state, "degraded")) {
|
|
|
|
*on = ansi_highlight_yellow();
|
|
|
|
*off = ansi_normal();
|
|
|
|
} else
|
|
|
|
*on = *off = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
static void setup_state_to_color(const char *state, const char **on, const char **off) {
|
|
|
|
assert(on);
|
|
|
|
assert(off);
|
|
|
|
|
|
|
|
if (streq_ptr(state, "configured")) {
|
|
|
|
*on = ansi_highlight_green();
|
|
|
|
*off = ansi_normal();
|
|
|
|
} else if (streq_ptr(state, "configuring")) {
|
|
|
|
*on = ansi_highlight_yellow();
|
|
|
|
*off = ansi_normal();
|
2016-09-25 02:18:02 +02:00
|
|
|
} else if (STRPTR_IN_SET(state, "failed", "linger")) {
|
2016-02-19 19:21:30 +01:00
|
|
|
*on = ansi_highlight_red();
|
|
|
|
*off = ansi_normal();
|
|
|
|
} else
|
|
|
|
*on = *off = "";
|
|
|
|
}
|
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
typedef struct VxLanInfo {
|
|
|
|
uint32_t vni;
|
|
|
|
uint32_t link;
|
|
|
|
|
|
|
|
int local_family;
|
|
|
|
int group_family;
|
|
|
|
|
|
|
|
union in_addr_union local;
|
|
|
|
union in_addr_union group;
|
|
|
|
|
|
|
|
uint16_t dest_port;
|
|
|
|
|
2020-03-23 16:24:04 +01:00
|
|
|
uint8_t proxy;
|
|
|
|
uint8_t learning;
|
|
|
|
uint8_t inerit;
|
|
|
|
uint8_t rsc;
|
|
|
|
uint8_t l2miss;
|
|
|
|
uint8_t l3miss;
|
|
|
|
uint8_t tos;
|
|
|
|
uint8_t ttl;
|
2019-07-25 19:09:34 +02:00
|
|
|
} VxLanInfo;
|
|
|
|
|
2014-08-12 16:03:45 +02:00
|
|
|
typedef struct LinkInfo {
|
2016-02-19 18:57:11 +01:00
|
|
|
char name[IFNAMSIZ+1];
|
2019-07-25 19:09:34 +02:00
|
|
|
char netdev_kind[NETDEV_KIND_MAX];
|
2019-10-23 17:02:18 +02:00
|
|
|
sd_device *sd_device;
|
2014-08-12 16:03:45 +02:00
|
|
|
int ifindex;
|
2016-02-18 22:47:34 +01:00
|
|
|
unsigned short iftype;
|
2016-02-19 19:18:12 +01:00
|
|
|
struct ether_addr mac_address;
|
2019-01-07 12:16:20 +01:00
|
|
|
struct ether_addr permanent_mac_address;
|
2020-03-14 10:09:48 +01:00
|
|
|
uint32_t master;
|
2016-02-19 19:18:12 +01:00
|
|
|
uint32_t mtu;
|
2019-05-21 14:14:36 +02:00
|
|
|
uint32_t min_mtu;
|
|
|
|
uint32_t max_mtu;
|
2019-05-22 10:53:12 +02:00
|
|
|
uint32_t tx_queues;
|
|
|
|
uint32_t rx_queues;
|
2020-03-18 13:42:27 +01:00
|
|
|
uint8_t addr_gen_mode;
|
2020-03-13 10:54:35 +01:00
|
|
|
char *qdisc;
|
2019-12-15 20:27:27 +01:00
|
|
|
char **alternative_names;
|
2016-02-19 19:18:12 +01:00
|
|
|
|
2019-05-24 17:37:48 +02:00
|
|
|
union {
|
|
|
|
struct rtnl_link_stats64 stats64;
|
|
|
|
struct rtnl_link_stats stats;
|
|
|
|
};
|
|
|
|
|
2019-06-19 15:18:54 +02:00
|
|
|
uint64_t tx_bitrate;
|
|
|
|
uint64_t rx_bitrate;
|
2019-05-25 17:22:05 +02:00
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
/* bridge info */
|
|
|
|
uint32_t forward_delay;
|
|
|
|
uint32_t hello_time;
|
|
|
|
uint32_t max_age;
|
|
|
|
uint32_t ageing_time;
|
|
|
|
uint32_t stp_state;
|
2020-03-22 14:27:30 +01:00
|
|
|
uint32_t cost;
|
2019-07-25 19:09:34 +02:00
|
|
|
uint16_t priority;
|
|
|
|
uint8_t mcast_igmp_version;
|
2020-03-22 14:27:30 +01:00
|
|
|
uint8_t port_state;
|
2019-07-25 19:09:34 +02:00
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
/* vxlan info */
|
|
|
|
VxLanInfo vxlan_info;
|
|
|
|
|
2020-03-16 14:36:26 +01:00
|
|
|
/* vlan info */
|
|
|
|
uint16_t vlan_id;
|
|
|
|
|
2020-03-17 06:08:05 +01:00
|
|
|
/* tunnel info */
|
2020-03-17 10:56:57 +01:00
|
|
|
uint8_t ttl;
|
|
|
|
uint8_t tos;
|
2020-03-25 14:52:52 +01:00
|
|
|
uint8_t inherit;
|
|
|
|
uint8_t df;
|
|
|
|
uint8_t csum;
|
|
|
|
uint8_t csum6_tx;
|
|
|
|
uint8_t csum6_rx;
|
2020-03-17 10:56:57 +01:00
|
|
|
uint16_t tunnel_port;
|
|
|
|
uint32_t vni;
|
2020-03-25 14:52:52 +01:00
|
|
|
uint32_t label;
|
2020-03-17 06:08:05 +01:00
|
|
|
union in_addr_union local;
|
|
|
|
union in_addr_union remote;
|
|
|
|
|
2020-03-18 08:50:15 +01:00
|
|
|
/* bonding info */
|
|
|
|
uint8_t mode;
|
|
|
|
uint32_t miimon;
|
|
|
|
uint32_t updelay;
|
|
|
|
uint32_t downdelay;
|
|
|
|
|
2020-03-19 05:24:49 +01:00
|
|
|
/* macvlan and macvtap info */
|
|
|
|
uint32_t macvlan_mode;
|
|
|
|
|
2019-06-17 09:12:06 +02:00
|
|
|
/* ethtool info */
|
|
|
|
int autonegotiation;
|
2020-01-21 12:06:40 +01:00
|
|
|
uint64_t speed;
|
2019-06-17 09:12:06 +02:00
|
|
|
Duplex duplex;
|
|
|
|
NetDevPort port;
|
|
|
|
|
2019-10-23 17:05:33 +02:00
|
|
|
/* wlan info */
|
2019-10-25 09:29:23 +02:00
|
|
|
enum nl80211_iftype wlan_iftype;
|
2019-10-23 17:05:33 +02:00
|
|
|
char *ssid;
|
|
|
|
struct ether_addr bssid;
|
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
bool has_mac_address:1;
|
2019-01-07 12:16:20 +01:00
|
|
|
bool has_permanent_mac_address:1;
|
2019-05-22 10:53:12 +02:00
|
|
|
bool has_tx_queues:1;
|
|
|
|
bool has_rx_queues:1;
|
2019-05-24 17:37:48 +02:00
|
|
|
bool has_stats64:1;
|
|
|
|
bool has_stats:1;
|
2019-05-25 17:22:05 +02:00
|
|
|
bool has_bitrates:1;
|
2019-06-17 09:12:06 +02:00
|
|
|
bool has_ethtool_link_info:1;
|
2019-10-23 17:05:33 +02:00
|
|
|
bool has_wlan_link_info:1;
|
2020-03-17 10:56:57 +01:00
|
|
|
bool has_tunnel_ipv4:1;
|
2020-03-18 13:42:27 +01:00
|
|
|
bool has_ipv6_address_generation_mode:1;
|
2019-10-23 17:02:18 +02:00
|
|
|
|
|
|
|
bool needs_freeing:1;
|
2014-08-12 16:03:45 +02:00
|
|
|
} LinkInfo;
|
|
|
|
|
2018-09-18 01:39:24 +02:00
|
|
|
static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
|
|
|
|
return CMP(a->ifindex, b->ifindex);
|
2014-08-12 16:03:45 +02:00
|
|
|
}
|
|
|
|
|
2019-10-23 17:02:18 +02:00
|
|
|
static const LinkInfo* link_info_array_free(LinkInfo *array) {
|
|
|
|
for (unsigned i = 0; array && array[i].needs_freeing; i++) {
|
|
|
|
sd_device_unref(array[i].sd_device);
|
2019-10-23 17:05:33 +02:00
|
|
|
free(array[i].ssid);
|
2020-03-13 10:54:35 +01:00
|
|
|
free(array[i].qdisc);
|
2019-12-15 20:27:27 +01:00
|
|
|
strv_free(array[i].alternative_names);
|
2019-10-23 17:02:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return mfree(array);
|
|
|
|
}
|
|
|
|
DEFINE_TRIVIAL_CLEANUP_FUNC(LinkInfo*, link_info_array_free);
|
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
|
|
|
|
const char *received_kind;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
assert(info);
|
|
|
|
|
|
|
|
r = sd_netlink_message_enter_container(m, IFLA_LINKINFO);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_string(m, IFLA_INFO_KIND, &received_kind);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_message_enter_container(m, IFLA_INFO_DATA);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (streq(received_kind, "bridge")) {
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BR_FORWARD_DELAY, &info->forward_delay);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BR_HELLO_TIME, &info->hello_time);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BR_MAX_AGE, &info->max_age);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BR_AGEING_TIME, &info->ageing_time);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state);
|
2020-03-22 14:27:30 +01:00
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BRPORT_COST, &info->cost);
|
2019-07-25 19:09:34 +02:00
|
|
|
(void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version);
|
2020-03-22 14:27:30 +01:00
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_BRPORT_STATE, &info->port_state);
|
2020-03-18 08:50:15 +01:00
|
|
|
} if (streq(received_kind, "bond")) {
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_BOND_MODE, &info->mode);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BOND_MIIMON, &info->miimon);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BOND_DOWNDELAY, &info->downdelay);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_BOND_UPDELAY, &info->updelay);
|
2019-07-25 19:09:34 +02:00
|
|
|
} else if (streq(received_kind, "vxlan")) {
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni);
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_GROUP, &info->vxlan_info.group.in);
|
|
|
|
if (r >= 0)
|
|
|
|
info->vxlan_info.group_family = AF_INET;
|
|
|
|
else {
|
|
|
|
r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_GROUP6, &info->vxlan_info.group.in6);
|
|
|
|
if (r >= 0)
|
|
|
|
info->vxlan_info.group_family = AF_INET6;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_LOCAL, &info->vxlan_info.local.in);
|
|
|
|
if (r >= 0)
|
|
|
|
info->vxlan_info.local_family = AF_INET;
|
|
|
|
else {
|
|
|
|
r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_LOCAL6, &info->vxlan_info.local.in6);
|
|
|
|
if (r >= 0)
|
|
|
|
info->vxlan_info.local_family = AF_INET6;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
|
|
|
|
(void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
|
2020-03-23 16:24:04 +01:00
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_VXLAN_PROXY, &info->vxlan_info.proxy);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_VXLAN_LEARNING, &info->vxlan_info.learning);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_VXLAN_RSC, &info->vxlan_info.rsc);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L3MISS, &info->vxlan_info.l3miss);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L2MISS, &info->vxlan_info.l2miss);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TOS, &info->vxlan_info.tos);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TTL, &info->vxlan_info.ttl);
|
2020-03-16 14:36:26 +01:00
|
|
|
} else if (streq(received_kind, "vlan"))
|
|
|
|
(void) sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &info->vlan_id);
|
2020-03-17 06:08:05 +01:00
|
|
|
else if (STR_IN_SET(received_kind, "ipip", "sit")) {
|
|
|
|
(void) sd_netlink_message_read_in_addr(m, IFLA_IPTUN_LOCAL, &info->local.in);
|
|
|
|
(void) sd_netlink_message_read_in_addr(m, IFLA_IPTUN_REMOTE, &info->remote.in);
|
2020-03-17 10:56:57 +01:00
|
|
|
} else if (streq(received_kind, "geneve")) {
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_GENEVE_ID, &info->vni);
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in_addr(m, IFLA_GENEVE_REMOTE, &info->remote.in);
|
|
|
|
if (r >= 0)
|
|
|
|
info->has_tunnel_ipv4 = true;
|
|
|
|
else
|
|
|
|
(void) sd_netlink_message_read_in6_addr(m, IFLA_GENEVE_REMOTE6, &info->remote.in6);
|
|
|
|
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TTL, &info->ttl);
|
2020-03-25 14:52:52 +01:00
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TTL_INHERIT, &info->inherit);
|
2020-03-17 10:56:57 +01:00
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TOS, &info->tos);
|
2020-03-25 14:52:52 +01:00
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_GENEVE_DF, &info->df);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_CSUM, &info->csum);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, &info->csum6_tx);
|
|
|
|
(void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, &info->csum6_rx);
|
2020-03-17 10:56:57 +01:00
|
|
|
(void) sd_netlink_message_read_u16(m, IFLA_GENEVE_PORT, &info->tunnel_port);
|
2020-03-25 14:52:52 +01:00
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_GENEVE_LABEL, &info->label);
|
2020-03-17 14:31:54 +01:00
|
|
|
} else if (STR_IN_SET(received_kind, "gre", "gretap", "erspan")) {
|
|
|
|
(void) sd_netlink_message_read_in_addr(m, IFLA_GRE_LOCAL, &info->local.in);
|
|
|
|
(void) sd_netlink_message_read_in_addr(m, IFLA_GRE_REMOTE, &info->remote.in);
|
2020-03-18 04:27:09 +01:00
|
|
|
} else if (STR_IN_SET(received_kind, "ip6gre", "ip6gretap", "ip6erspan")) {
|
|
|
|
(void) sd_netlink_message_read_in6_addr(m, IFLA_GRE_LOCAL, &info->local.in6);
|
|
|
|
(void) sd_netlink_message_read_in6_addr(m, IFLA_GRE_REMOTE, &info->remote.in6);
|
2020-03-18 05:21:41 +01:00
|
|
|
} else if (streq(received_kind, "vti")) {
|
|
|
|
(void) sd_netlink_message_read_in_addr(m, IFLA_VTI_LOCAL, &info->local.in);
|
|
|
|
(void) sd_netlink_message_read_in_addr(m, IFLA_VTI_REMOTE, &info->remote.in);
|
|
|
|
} else if (streq(received_kind, "vti6")) {
|
|
|
|
(void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_LOCAL, &info->local.in6);
|
|
|
|
(void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_REMOTE, &info->remote.in6);
|
2020-03-19 05:24:49 +01:00
|
|
|
} else if (STR_IN_SET(received_kind, "macvlan", "macvtap"))
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_MACVLAN_MODE, &info->macvlan_mode);
|
2019-07-25 19:09:34 +02:00
|
|
|
|
|
|
|
strncpy(info->netdev_kind, received_kind, IFNAMSIZ);
|
|
|
|
|
|
|
|
(void) sd_netlink_message_exit_container(m);
|
|
|
|
(void) sd_netlink_message_exit_container(m);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-12 12:14:31 +01:00
|
|
|
static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, bool matched_patterns[]) {
|
2019-12-17 13:07:46 +01:00
|
|
|
_cleanup_strv_free_ char **altnames = NULL;
|
2020-03-13 10:54:35 +01:00
|
|
|
const char *name, *qdisc;
|
2019-02-15 05:32:51 +01:00
|
|
|
int ifindex, r;
|
2019-07-25 19:09:34 +02:00
|
|
|
uint16_t type;
|
2014-08-12 16:03:45 +02:00
|
|
|
|
2016-02-19 18:57:11 +01:00
|
|
|
assert(m);
|
|
|
|
assert(info);
|
2014-08-12 16:03:45 +02:00
|
|
|
|
2016-02-19 18:57:11 +01:00
|
|
|
r = sd_netlink_message_get_type(m, &type);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-08-12 16:03:45 +02:00
|
|
|
|
2016-02-19 18:57:11 +01:00
|
|
|
if (type != RTM_NEWLINK)
|
|
|
|
return 0;
|
2014-08-12 16:03:45 +02:00
|
|
|
|
2019-02-15 05:32:51 +01:00
|
|
|
r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
|
2016-02-19 18:57:11 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-08-12 16:03:45 +02:00
|
|
|
|
2016-02-19 18:57:11 +01:00
|
|
|
r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-08-12 16:03:45 +02:00
|
|
|
|
2019-12-17 13:07:46 +01:00
|
|
|
r = sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &altnames);
|
|
|
|
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENODATA))
|
|
|
|
return r;
|
|
|
|
|
2019-02-15 05:32:51 +01:00
|
|
|
if (patterns) {
|
|
|
|
char str[DECIMAL_STR_MAX(int)];
|
2020-01-12 12:14:31 +01:00
|
|
|
size_t pos;
|
|
|
|
|
|
|
|
assert(matched_patterns);
|
2019-02-15 05:32:51 +01:00
|
|
|
|
|
|
|
xsprintf(str, "%i", ifindex);
|
2020-01-12 12:14:31 +01:00
|
|
|
if (!strv_fnmatch_full(patterns, str, 0, &pos) &&
|
|
|
|
!strv_fnmatch_full(patterns, name, 0, &pos)) {
|
2019-12-17 13:07:46 +01:00
|
|
|
bool match = false;
|
|
|
|
char **p;
|
|
|
|
|
|
|
|
STRV_FOREACH(p, altnames)
|
2020-01-12 12:14:31 +01:00
|
|
|
if (strv_fnmatch_full(patterns, *p, 0, &pos)) {
|
2019-12-17 13:07:46 +01:00
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!match)
|
|
|
|
return 0;
|
|
|
|
}
|
2020-01-12 12:14:31 +01:00
|
|
|
|
|
|
|
matched_patterns[pos] = true;
|
2019-02-15 05:32:51 +01:00
|
|
|
}
|
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
r = sd_rtnl_message_link_get_type(m, &info->iftype);
|
2016-02-19 18:57:11 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-08-12 16:03:45 +02:00
|
|
|
|
2016-03-02 21:43:41 +01:00
|
|
|
strscpy(info->name, sizeof info->name, name);
|
2019-02-15 05:32:51 +01:00
|
|
|
info->ifindex = ifindex;
|
2019-12-17 13:07:46 +01:00
|
|
|
info->alternative_names = TAKE_PTR(altnames);
|
2016-02-19 19:18:12 +01:00
|
|
|
|
|
|
|
info->has_mac_address =
|
|
|
|
sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
|
2016-03-02 21:43:30 +01:00
|
|
|
memcmp(&info->mac_address, ÐER_ADDR_NULL, sizeof(struct ether_addr)) != 0;
|
2016-02-19 19:18:12 +01:00
|
|
|
|
2019-01-07 12:16:20 +01:00
|
|
|
info->has_permanent_mac_address =
|
2020-01-08 12:02:01 +01:00
|
|
|
ethtool_get_permanent_macaddr(NULL, info->name, &info->permanent_mac_address) >= 0 &&
|
2019-01-07 12:16:20 +01:00
|
|
|
memcmp(&info->permanent_mac_address, ÐER_ADDR_NULL, sizeof(struct ether_addr)) != 0 &&
|
|
|
|
memcmp(&info->permanent_mac_address, &info->mac_address, sizeof(struct ether_addr)) != 0;
|
|
|
|
|
2019-05-30 20:30:31 +02:00
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu);
|
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu);
|
2019-05-21 14:14:36 +02:00
|
|
|
|
2019-05-22 10:53:12 +02:00
|
|
|
info->has_rx_queues =
|
|
|
|
sd_netlink_message_read_u32(m, IFLA_NUM_RX_QUEUES, &info->rx_queues) >= 0 &&
|
|
|
|
info->rx_queues > 0;
|
|
|
|
|
|
|
|
info->has_tx_queues =
|
|
|
|
sd_netlink_message_read_u32(m, IFLA_NUM_TX_QUEUES, &info->tx_queues) >= 0 &&
|
|
|
|
info->tx_queues > 0;
|
|
|
|
|
2019-05-24 17:37:48 +02:00
|
|
|
if (sd_netlink_message_read(m, IFLA_STATS64, sizeof info->stats64, &info->stats64) >= 0)
|
|
|
|
info->has_stats64 = true;
|
|
|
|
else if (sd_netlink_message_read(m, IFLA_STATS, sizeof info->stats, &info->stats) >= 0)
|
|
|
|
info->has_stats = true;
|
|
|
|
|
2020-03-13 10:54:35 +01:00
|
|
|
r = sd_netlink_message_read_string(m, IFLA_QDISC, &qdisc);
|
|
|
|
if (r >= 0) {
|
|
|
|
info->qdisc = strdup(qdisc);
|
|
|
|
if (!info->qdisc)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
2020-03-14 10:09:48 +01:00
|
|
|
(void) sd_netlink_message_read_u32(m, IFLA_MASTER, &info->master);
|
|
|
|
|
2020-03-18 13:42:27 +01:00
|
|
|
r = sd_netlink_message_enter_container(m, IFLA_AF_SPEC);
|
|
|
|
if (r >= 0) {
|
|
|
|
r = sd_netlink_message_enter_container(m, AF_INET6);
|
|
|
|
if (r >= 0) {
|
|
|
|
r = sd_netlink_message_read_u8(m, IFLA_INET6_ADDR_GEN_MODE, &info->addr_gen_mode);
|
|
|
|
if (r >= 0)
|
|
|
|
info->has_ipv6_address_generation_mode = true;
|
|
|
|
|
|
|
|
(void) sd_netlink_message_exit_container(m);
|
|
|
|
}
|
|
|
|
(void) sd_netlink_message_exit_container(m);
|
|
|
|
}
|
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
/* fill kind info */
|
|
|
|
(void) decode_netdev(m, info);
|
|
|
|
|
2016-02-19 18:57:11 +01:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_free_ char *path = NULL, *ifindex_str = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (asprintf(&ifindex_str, "%i", link->ifindex) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_bus_call_method(
|
|
|
|
bus,
|
|
|
|
"org.freedesktop.network1",
|
|
|
|
path,
|
|
|
|
"org.freedesktop.DBus.Properties",
|
|
|
|
"Get",
|
|
|
|
&error,
|
|
|
|
&reply,
|
|
|
|
"ss",
|
|
|
|
"org.freedesktop.network1.Link",
|
|
|
|
"BitRates");
|
|
|
|
if (r < 0) {
|
2019-12-17 12:32:36 +01:00
|
|
|
bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY) ||
|
|
|
|
sd_bus_error_has_name(&error, BUS_ERROR_SPEED_METER_INACTIVE);
|
2019-05-31 16:08:31 +02:00
|
|
|
|
|
|
|
return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
|
|
|
|
r, "Failed to query link bit rates: %s", bus_error_message(&error, r));
|
2019-05-25 17:22:05 +02:00
|
|
|
}
|
|
|
|
|
2019-06-19 15:18:54 +02:00
|
|
|
r = sd_bus_message_enter_container(reply, 'v', "(tt)");
|
2019-05-25 17:22:05 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2019-06-19 15:18:54 +02:00
|
|
|
r = sd_bus_message_read(reply, "(tt)", &link->tx_bitrate, &link->rx_bitrate);
|
2019-05-25 17:22:05 +02:00
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
r = sd_bus_message_exit_container(reply);
|
|
|
|
if (r < 0)
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
2019-12-02 16:29:44 +01:00
|
|
|
link->has_bitrates = link->tx_bitrate != UINT64_MAX && link->rx_bitrate != UINT64_MAX;
|
2019-05-25 17:22:05 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-23 12:24:42 +02:00
|
|
|
static void acquire_ether_link_info(int *fd, LinkInfo *link) {
|
|
|
|
if (ethtool_get_link_info(fd, link->name,
|
|
|
|
&link->autonegotiation,
|
|
|
|
&link->speed,
|
|
|
|
&link->duplex,
|
|
|
|
&link->port) >= 0)
|
|
|
|
link->has_ethtool_link_info = true;
|
|
|
|
}
|
|
|
|
|
2019-10-23 17:05:33 +02:00
|
|
|
static void acquire_wlan_link_info(LinkInfo *link) {
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
|
|
|
|
const char *type = NULL;
|
2019-10-25 09:29:23 +02:00
|
|
|
int r, k = 0;
|
2019-10-23 17:05:33 +02:00
|
|
|
|
|
|
|
if (link->sd_device)
|
|
|
|
(void) sd_device_get_devtype(link->sd_device, &type);
|
|
|
|
if (!streq_ptr(type, "wlan"))
|
|
|
|
return;
|
|
|
|
|
|
|
|
r = sd_genl_socket_open(&genl);
|
|
|
|
if (r < 0) {
|
|
|
|
log_debug_errno(r, "Failed to open generic netlink socket: %m");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) sd_netlink_inc_rcvbuf(genl, RCVBUF_SIZE);
|
|
|
|
|
2019-10-25 09:29:23 +02:00
|
|
|
r = wifi_get_interface(genl, link->ifindex, &link->wlan_iftype, &link->ssid);
|
2019-10-23 17:05:33 +02:00
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "%s: failed to query ssid: %m", link->name);
|
|
|
|
|
2019-12-02 16:39:28 +01:00
|
|
|
if (link->wlan_iftype == NL80211_IFTYPE_STATION) {
|
2019-10-25 09:29:23 +02:00
|
|
|
k = wifi_get_station(genl, link->ifindex, &link->bssid);
|
|
|
|
if (k < 0)
|
|
|
|
log_debug_errno(k, "%s: failed to query bssid: %m", link->name);
|
|
|
|
}
|
2019-10-23 17:05:33 +02:00
|
|
|
|
|
|
|
link->has_wlan_link_info = r > 0 || k > 0;
|
|
|
|
}
|
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2019-10-23 17:02:18 +02:00
|
|
|
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
|
2019-06-17 09:12:06 +02:00
|
|
|
_cleanup_close_ int fd = -1;
|
2019-05-25 17:22:05 +02:00
|
|
|
size_t allocated = 0, c = 0, j;
|
2016-02-19 19:21:30 +01:00
|
|
|
sd_netlink_message *i;
|
2016-02-19 18:26:18 +01:00
|
|
|
int r;
|
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
assert(rtnl);
|
2016-02-19 18:26:18 +01:00
|
|
|
assert(ret);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-08-12 01:41:42 +02:00
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to enumerate links: %m");
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2020-01-12 12:14:31 +01:00
|
|
|
_cleanup_free_ bool *matched_patterns = NULL;
|
|
|
|
if (patterns) {
|
|
|
|
matched_patterns = new0(bool, strv_length(patterns));
|
|
|
|
if (!matched_patterns)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
2016-02-19 19:21:30 +01:00
|
|
|
for (i = reply; i; i = sd_netlink_message_next(i)) {
|
2019-10-23 17:02:18 +02:00
|
|
|
if (!GREEDY_REALLOC0(links, allocated, c + 2)) /* We keep one trailing one as marker */
|
2016-02-19 19:21:30 +01:00
|
|
|
return -ENOMEM;
|
2016-02-19 18:26:18 +01:00
|
|
|
|
2020-01-12 12:14:31 +01:00
|
|
|
r = decode_link(i, links + c, patterns, matched_patterns);
|
2016-02-19 19:21:30 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-06-17 09:12:06 +02:00
|
|
|
if (r == 0)
|
|
|
|
continue;
|
|
|
|
|
2019-10-23 17:02:18 +02:00
|
|
|
links[c].needs_freeing = true;
|
|
|
|
|
|
|
|
char devid[2 + DECIMAL_STR_MAX(int)];
|
|
|
|
xsprintf(devid, "n%i", links[c].ifindex);
|
|
|
|
(void) sd_device_new_from_device_id(&links[c].sd_device, devid);
|
|
|
|
|
2019-10-23 12:24:42 +02:00
|
|
|
acquire_ether_link_info(&fd, &links[c]);
|
2019-10-23 17:05:33 +02:00
|
|
|
acquire_wlan_link_info(&links[c]);
|
2019-06-17 09:12:06 +02:00
|
|
|
|
|
|
|
c++;
|
2016-02-19 19:21:30 +01:00
|
|
|
}
|
|
|
|
|
2020-01-12 12:14:31 +01:00
|
|
|
/* Look if we matched all our arguments that are not globs. It
|
|
|
|
* is OK for a glob to match nothing, but not for an exact argument. */
|
|
|
|
for (size_t pos = 0; pos < strv_length(patterns); pos++) {
|
|
|
|
if (matched_patterns[pos])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (string_is_glob(patterns[pos]))
|
|
|
|
log_debug("Pattern \"%s\" doesn't match any interface, ignoring.",
|
|
|
|
patterns[pos]);
|
|
|
|
else
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
|
|
|
|
"Interface \"%s\" not found.", patterns[pos]);
|
|
|
|
}
|
|
|
|
|
2018-09-18 01:39:24 +02:00
|
|
|
typesafe_qsort(links, c, link_info_compare);
|
2016-02-19 19:21:30 +01:00
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
if (bus)
|
|
|
|
for (j = 0; j < c; j++)
|
|
|
|
(void) acquire_link_bitrates(bus, links + j);
|
|
|
|
|
2018-04-05 07:26:26 +02:00
|
|
|
*ret = TAKE_PTR(links);
|
2016-02-19 19:21:30 +01:00
|
|
|
|
2020-01-12 12:14:31 +01:00
|
|
|
if (patterns && c == 0)
|
|
|
|
log_warning("No interfaces matched.");
|
|
|
|
|
2016-02-19 19:21:30 +01:00
|
|
|
return (int) c;
|
2016-02-19 18:26:18 +01:00
|
|
|
}
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2016-02-19 18:26:18 +01:00
|
|
|
static int list_links(int argc, char *argv[], void *userdata) {
|
2016-02-19 19:18:12 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2019-10-23 17:02:18 +02:00
|
|
|
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
|
2019-05-22 19:21:17 +02:00
|
|
|
_cleanup_(table_unrefp) Table *table = NULL;
|
|
|
|
TableCell *cell;
|
2016-02-19 19:18:12 +01:00
|
|
|
int c, i, r;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
2016-02-19 18:26:18 +01:00
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
|
2014-08-12 16:03:45 +02:00
|
|
|
if (c < 0)
|
2016-02-19 18:26:18 +01:00
|
|
|
return c;
|
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
2016-02-19 18:26:18 +01:00
|
|
|
|
2019-07-16 13:32:51 +02:00
|
|
|
table = table_new("idx", "link", "type", "operational", "setup");
|
2019-05-22 19:21:17 +02:00
|
|
|
if (!table)
|
|
|
|
return log_oom();
|
|
|
|
|
2020-01-10 04:12:00 +01:00
|
|
|
if (arg_full)
|
|
|
|
table_set_width(table, 0);
|
|
|
|
|
2019-05-22 19:21:17 +02:00
|
|
|
table_set_header(table, arg_legend);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 0));
|
|
|
|
(void) table_set_minimum_width(table, cell, 3);
|
|
|
|
(void) table_set_weight(table, cell, 0);
|
2019-06-03 09:04:16 +02:00
|
|
|
(void) table_set_ellipsize_percent(table, cell, 100);
|
2019-05-22 19:21:17 +02:00
|
|
|
(void) table_set_align_percent(table, cell, 100);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 1));
|
2019-06-03 09:04:16 +02:00
|
|
|
(void) table_set_ellipsize_percent(table, cell, 100);
|
2014-08-12 16:03:45 +02:00
|
|
|
|
|
|
|
for (i = 0; i < c; i++) {
|
2014-08-14 01:10:08 +02:00
|
|
|
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
|
2014-08-14 01:18:37 +02:00
|
|
|
const char *on_color_operational, *off_color_operational,
|
|
|
|
*on_color_setup, *off_color_setup;
|
2014-08-12 01:41:42 +02:00
|
|
|
_cleanup_free_ char *t = NULL;
|
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
|
2019-10-23 11:10:32 +02:00
|
|
|
operational_state_to_color(links[i].name, operational_state, &on_color_operational, &off_color_operational);
|
2014-08-14 01:18:37 +02:00
|
|
|
|
2016-02-20 22:12:14 +01:00
|
|
|
r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
|
|
|
|
if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
|
|
|
|
setup_state = strdup("unmanaged");
|
2014-08-14 01:18:37 +02:00
|
|
|
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2019-10-23 17:02:18 +02:00
|
|
|
t = link_get_type_string(links[i].iftype, links[i].sd_device);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2019-05-22 19:21:17 +02:00
|
|
|
r = table_add_many(table,
|
2019-07-28 06:07:19 +02:00
|
|
|
TABLE_INT, links[i].ifindex,
|
2019-05-22 19:21:17 +02:00
|
|
|
TABLE_STRING, links[i].name,
|
2019-07-28 06:07:19 +02:00
|
|
|
TABLE_STRING, strna(t),
|
|
|
|
TABLE_STRING, strna(operational_state),
|
|
|
|
TABLE_SET_COLOR, on_color_operational,
|
|
|
|
TABLE_STRING, strna(setup_state),
|
|
|
|
TABLE_SET_COLOR, on_color_setup);
|
2019-05-22 19:21:17 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
2019-05-22 19:21:17 +02:00
|
|
|
r = table_print(table, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to print table: %m");
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
if (arg_legend)
|
2014-08-12 16:03:45 +02:00
|
|
|
printf("\n%i links listed.\n", c);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-02 01:05:52 +01:00
|
|
|
/* IEEE Organizationally Unique Identifier vendor string */
|
2016-02-19 19:18:12 +01:00
|
|
|
static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
|
2014-12-15 20:07:34 +01:00
|
|
|
const char *description;
|
2017-12-14 19:02:29 +01:00
|
|
|
char modalias[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc;
|
2014-12-15 20:07:34 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(ret);
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-12 18:50:06 +01:00
|
|
|
if (!hwdb)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
if (!mac)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-12-02 01:05:52 +01:00
|
|
|
/* skip commonly misused 00:00:00 (Xerox) prefix */
|
|
|
|
if (memcmp(mac, "\0\0\0", 3) == 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2016-01-12 15:34:20 +01:00
|
|
|
xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,
|
|
|
|
ETHER_ADDR_FORMAT_VAL(*mac));
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
desc = strdup(description);
|
|
|
|
if (!desc)
|
|
|
|
return -ENOMEM;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
*ret = desc;
|
|
|
|
|
|
|
|
return 0;
|
2014-12-02 01:05:52 +01:00
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int get_gateway_description(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2014-12-15 20:07:34 +01:00
|
|
|
sd_hwdb *hwdb,
|
2014-12-12 18:57:15 +01:00
|
|
|
int ifindex,
|
|
|
|
int family,
|
|
|
|
union in_addr_union *gateway,
|
|
|
|
char **gateway_description) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink_message *m;
|
2014-12-02 01:05:52 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
assert(ifindex >= 0);
|
2017-10-04 16:01:32 +02:00
|
|
|
assert(IN_SET(family, AF_INET, AF_INET6));
|
2014-12-02 01:05:52 +01:00
|
|
|
assert(gateway);
|
|
|
|
assert(gateway_description);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
for (m = reply; m; m = sd_netlink_message_next(m)) {
|
2019-05-04 20:14:08 +02:00
|
|
|
union in_addr_union gw = IN_ADDR_NULL;
|
|
|
|
struct ether_addr mac = ETHER_ADDR_NULL;
|
2014-12-02 01:05:52 +01:00
|
|
|
uint16_t type;
|
|
|
|
int ifi, fam;
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_errno(m);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "got error: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_get_type(m, &type);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "could not get type: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (type != RTM_NEWNEIGH) {
|
|
|
|
log_error("type is not RTM_NEWNEIGH");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_neigh_get_family(m, &fam);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "could not get family: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fam != family) {
|
|
|
|
log_error("family is not correct");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
|
|
|
|
if (r < 0) {
|
2014-12-03 20:59:00 +01:00
|
|
|
log_error_errno(r, "could not get ifindex: %m");
|
2014-12-02 01:05:52 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ifindex > 0 && ifi != ifindex)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
switch (fam) {
|
|
|
|
case AF_INET:
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case AF_INET6:
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in_addr_equal(fam, &gw, gateway))
|
|
|
|
continue;
|
|
|
|
|
2019-07-11 03:17:30 +02:00
|
|
|
r = sd_netlink_message_read(m, NDA_LLADDR, sizeof(mac), &mac);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = ieee_oui(hwdb, &mac, gateway_description);
|
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENODATA;
|
|
|
|
}
|
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
static int dump_list(Table *table, const char *prefix, char * const *l) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (strv_isempty(l))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, prefix,
|
|
|
|
TABLE_STRV, l);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int dump_gateways(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2014-12-15 20:07:34 +01:00
|
|
|
sd_hwdb *hwdb,
|
2019-05-22 18:43:21 +02:00
|
|
|
Table *table,
|
2014-12-12 18:57:15 +01:00
|
|
|
int ifindex) {
|
2014-12-04 12:19:27 +01:00
|
|
|
_cleanup_free_ struct local_address *local = NULL;
|
2020-01-14 10:29:52 +01:00
|
|
|
_cleanup_strv_free_ char **buf = NULL;
|
2014-12-04 12:19:27 +01:00
|
|
|
int r, n, i;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2016-02-19 19:50:14 +01:00
|
|
|
assert(rtnl);
|
2019-05-22 18:43:21 +02:00
|
|
|
assert(table);
|
2016-02-19 19:50:14 +01:00
|
|
|
|
2014-12-04 12:19:27 +01:00
|
|
|
n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
|
2020-01-14 10:29:52 +01:00
|
|
|
if (n <= 0)
|
2014-12-04 12:19:27 +01:00
|
|
|
return n;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-04 12:19:27 +01:00
|
|
|
for (i = 0; i < n; i++) {
|
2019-05-22 18:43:21 +02:00
|
|
|
_cleanup_free_ char *gateway = NULL, *description = NULL, *with_description = NULL;
|
2020-01-14 10:29:52 +01:00
|
|
|
char name[IF_NAMESIZE+1];
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-04 12:19:27 +01:00
|
|
|
r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
2014-12-04 12:19:27 +01:00
|
|
|
return r;
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
|
2014-12-02 01:05:52 +01:00
|
|
|
if (r < 0)
|
2020-01-14 10:29:52 +01:00
|
|
|
log_debug_errno(r, "Could not get description of gateway, ignoring: %m");
|
2014-12-02 01:05:52 +01:00
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
if (description) {
|
|
|
|
with_description = strjoin(gateway, " (", description, ")");
|
|
|
|
if (!with_description)
|
2020-01-14 10:29:52 +01:00
|
|
|
return log_oom();
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
2014-12-12 19:07:26 +01:00
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
/* Show interface name for the entry if we show entries for all interfaces */
|
|
|
|
r = strv_extendf(&buf, "%s%s%s",
|
|
|
|
with_description ?: gateway,
|
|
|
|
ifindex <= 0 ? " on " : "",
|
|
|
|
ifindex <= 0 ? format_ifname_full(local[i].ifindex, name, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-14 10:29:52 +01:00
|
|
|
return log_oom();
|
2014-12-02 01:05:52 +01:00
|
|
|
}
|
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
return dump_list(table, "Gateway:", buf);
|
2014-12-02 01:05:52 +01:00
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int dump_addresses(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2019-05-22 18:43:21 +02:00
|
|
|
Table *table,
|
2014-12-12 18:57:15 +01:00
|
|
|
int ifindex) {
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
_cleanup_free_ struct local_address *local = NULL;
|
2019-09-09 16:27:40 +02:00
|
|
|
_cleanup_free_ char *dhcp4_address = NULL;
|
2020-01-14 10:29:52 +01:00
|
|
|
_cleanup_strv_free_ char **buf = NULL;
|
2014-08-12 01:41:42 +02:00
|
|
|
int r, n, i;
|
|
|
|
|
2016-02-19 19:50:14 +01:00
|
|
|
assert(rtnl);
|
2019-05-22 18:43:21 +02:00
|
|
|
assert(table);
|
2016-02-19 19:50:14 +01:00
|
|
|
|
2014-12-04 01:41:12 +01:00
|
|
|
n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
|
2020-01-14 10:29:52 +01:00
|
|
|
if (n <= 0)
|
2014-08-12 01:41:42 +02:00
|
|
|
return n;
|
|
|
|
|
2019-09-09 16:27:40 +02:00
|
|
|
(void) sd_network_link_get_dhcp4_address(ifindex, &dhcp4_address);
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
_cleanup_free_ char *pretty = NULL;
|
2020-01-14 10:29:52 +01:00
|
|
|
char name[IF_NAMESIZE+1];
|
2014-12-12 19:07:26 +01:00
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-12-12 19:07:26 +01:00
|
|
|
|
2019-09-09 16:27:40 +02:00
|
|
|
if (dhcp4_address && streq(pretty, dhcp4_address)) {
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
|
|
|
|
p = pretty;
|
|
|
|
pretty = strjoin(pretty , " (DHCP4)");
|
|
|
|
if (!pretty)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
r = strv_extendf(&buf, "%s%s%s",
|
|
|
|
pretty,
|
|
|
|
ifindex <= 0 ? " on " : "",
|
|
|
|
ifindex <= 0 ? format_ifname_full(local[i].ifindex, name, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-14 10:29:52 +01:00
|
|
|
return log_oom();
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
return dump_list(table, "Address:", buf);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
2017-06-26 19:58:10 +02:00
|
|
|
static int dump_address_labels(sd_netlink *rtnl) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
2019-05-22 22:03:42 +02:00
|
|
|
_cleanup_(table_unrefp) Table *table = NULL;
|
2017-06-26 19:58:10 +02:00
|
|
|
sd_netlink_message *m;
|
2019-05-22 22:03:42 +02:00
|
|
|
TableCell *cell;
|
2017-06-26 19:58:10 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABEL, 0, AF_INET6);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_message_request_dump(req, true);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, req, 0, &reply);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2019-07-16 13:32:51 +02:00
|
|
|
table = table_new("label", "prefix/prefixlen");
|
2019-05-22 22:03:42 +02:00
|
|
|
if (!table)
|
2020-01-10 10:23:24 +01:00
|
|
|
return log_oom();
|
2019-05-22 22:03:42 +02:00
|
|
|
|
2020-01-10 04:12:00 +01:00
|
|
|
if (arg_full)
|
|
|
|
table_set_width(table, 0);
|
|
|
|
|
2020-02-14 09:33:43 +01:00
|
|
|
r = table_set_sort(table, (size_t) 0, (size_t) SIZE_MAX);
|
2019-05-22 22:03:42 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 0));
|
|
|
|
(void) table_set_align_percent(table, cell, 100);
|
2019-06-03 09:04:16 +02:00
|
|
|
(void) table_set_ellipsize_percent(table, cell, 100);
|
2019-05-22 22:03:42 +02:00
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 1));
|
|
|
|
(void) table_set_align_percent(table, cell, 100);
|
2017-06-26 19:58:10 +02:00
|
|
|
|
|
|
|
for (m = reply; m; m = sd_netlink_message_next(m)) {
|
|
|
|
_cleanup_free_ char *pretty = NULL;
|
2019-05-04 20:14:08 +02:00
|
|
|
union in_addr_union prefix = IN_ADDR_NULL;
|
2017-06-26 19:58:10 +02:00
|
|
|
uint8_t prefixlen;
|
|
|
|
uint32_t label;
|
|
|
|
|
|
|
|
r = sd_netlink_message_get_errno(m);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "got error: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label);
|
|
|
|
if (r < 0 && r != -ENODATA) {
|
|
|
|
log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6);
|
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = in_addr_to_string(AF_INET6, &prefix, &pretty);
|
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen);
|
|
|
|
if (r < 0)
|
|
|
|
continue;
|
|
|
|
|
2019-06-03 09:04:16 +02:00
|
|
|
r = table_add_cell(table, NULL, TABLE_UINT32, &label);
|
2019-05-22 22:03:42 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 22:03:42 +02:00
|
|
|
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_cell_stringf(table, NULL, "%s/%u", pretty, prefixlen);
|
2019-05-22 22:03:42 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2017-06-26 19:58:10 +02:00
|
|
|
}
|
|
|
|
|
2020-01-10 10:23:24 +01:00
|
|
|
r = table_print(table, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to print table: %m");
|
|
|
|
|
|
|
|
return 0;
|
2017-06-26 19:58:10 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int list_address_labels(int argc, char *argv[], void *userdata) {
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
dump_address_labels(rtnl);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-19 19:50:14 +01:00
|
|
|
static int open_lldp_neighbors(int ifindex, FILE **ret) {
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
f = fopen(p, "re");
|
|
|
|
if (!f)
|
|
|
|
return -errno;
|
|
|
|
|
|
|
|
*ret = f;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
|
|
|
|
_cleanup_free_ void *raw = NULL;
|
|
|
|
size_t l;
|
|
|
|
le64_t u;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(f);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
l = fread(&u, 1, sizeof(u), f);
|
|
|
|
if (l == 0 && feof(f))
|
|
|
|
return 0;
|
|
|
|
if (l != sizeof(u))
|
|
|
|
return -EBADMSG;
|
|
|
|
|
2018-06-07 22:46:32 +02:00
|
|
|
/* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
|
|
|
|
if (le64toh(u) >= 4096)
|
|
|
|
return -EBADMSG;
|
|
|
|
|
2016-02-19 19:50:14 +01:00
|
|
|
raw = new(uint8_t, le64toh(u));
|
|
|
|
if (!raw)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
if (fread(raw, 1, le64toh(u), f) != le64toh(u))
|
|
|
|
return -EBADMSG;
|
|
|
|
|
|
|
|
r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
static int dump_lldp_neighbors(Table *table, const char *prefix, int ifindex) {
|
2020-01-14 10:29:52 +01:00
|
|
|
_cleanup_strv_free_ char **buf = NULL;
|
2016-02-19 19:50:14 +01:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
2020-01-14 10:29:52 +01:00
|
|
|
int r;
|
2016-02-19 19:50:14 +01:00
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
assert(table);
|
2016-02-19 19:50:14 +01:00
|
|
|
assert(prefix);
|
|
|
|
assert(ifindex > 0);
|
|
|
|
|
|
|
|
r = open_lldp_neighbors(ifindex, &f);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r == -ENOENT)
|
|
|
|
return 0;
|
2016-02-19 19:50:14 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
|
|
|
|
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
|
|
|
|
|
|
|
r = next_lldp_neighbor(f, &n);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
(void) sd_lldp_neighbor_get_system_name(n, &system_name);
|
|
|
|
(void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
|
|
|
|
(void) sd_lldp_neighbor_get_port_description(n, &port_description);
|
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
r = strv_extendf(&buf, "%s on port %s%s%s%s",
|
|
|
|
strna(system_name),
|
|
|
|
strna(port_id),
|
|
|
|
isempty(port_description) ? "" : " (",
|
|
|
|
strempty(port_description),
|
|
|
|
isempty(port_description) ? "" : ")");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-14 10:29:52 +01:00
|
|
|
return log_oom();
|
2016-02-19 19:50:14 +01:00
|
|
|
}
|
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
return dump_list(table, prefix, buf);
|
2016-02-19 19:50:14 +01:00
|
|
|
}
|
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
static int dump_ifindexes(Table *table, const char *prefix, const int *ifindexes) {
|
2016-02-19 20:43:03 +01:00
|
|
|
unsigned c;
|
2019-05-22 18:43:21 +02:00
|
|
|
int r;
|
2016-02-19 20:43:03 +01:00
|
|
|
|
|
|
|
assert(prefix);
|
|
|
|
|
|
|
|
if (!ifindexes || ifindexes[0] <= 0)
|
2019-05-22 18:43:21 +02:00
|
|
|
return 0;
|
2016-02-19 20:43:03 +01:00
|
|
|
|
|
|
|
for (c = 0; ifindexes[c] > 0; c++) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, c == 0 ? prefix : "",
|
|
|
|
TABLE_IFINDEX, ifindexes[c]);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2016-02-19 20:43:03 +01:00
|
|
|
}
|
2019-05-22 18:43:21 +02:00
|
|
|
|
|
|
|
return 0;
|
2016-02-19 20:43:03 +01:00
|
|
|
}
|
|
|
|
|
2019-05-24 17:37:48 +02:00
|
|
|
#define DUMP_STATS_ONE(name, val_name) \
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table, \
|
|
|
|
TABLE_EMPTY, \
|
|
|
|
TABLE_STRING, name ":"); \
|
2019-05-24 17:37:48 +02:00
|
|
|
if (r < 0) \
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r); \
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_cell(table, NULL, \
|
|
|
|
info->has_stats64 ? TABLE_UINT64 : TABLE_UINT32, \
|
2019-05-24 17:37:48 +02:00
|
|
|
info->has_stats64 ? (void*) &info->stats64.val_name : (void*) &info->stats.val_name); \
|
|
|
|
if (r < 0) \
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-24 17:37:48 +02:00
|
|
|
|
|
|
|
static int dump_statistics(Table *table, const LinkInfo *info) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!arg_stats)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!info->has_stats64 && !info->has_stats)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
DUMP_STATS_ONE("Rx Packets", rx_packets);
|
|
|
|
DUMP_STATS_ONE("Tx Packets", tx_packets);
|
|
|
|
DUMP_STATS_ONE("Rx Bytes", rx_bytes);
|
|
|
|
DUMP_STATS_ONE("Tx Bytes", tx_bytes);
|
|
|
|
DUMP_STATS_ONE("Rx Errors", rx_errors);
|
|
|
|
DUMP_STATS_ONE("Tx Errors", tx_errors);
|
|
|
|
DUMP_STATS_ONE("Rx Dropped", rx_dropped);
|
|
|
|
DUMP_STATS_ONE("Tx Dropped", tx_dropped);
|
|
|
|
DUMP_STATS_ONE("Multicast Packets", multicast);
|
|
|
|
DUMP_STATS_ONE("Collisions", collisions);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-07 03:32:03 +01:00
|
|
|
static OutputFlags get_output_flags(void) {
|
|
|
|
return
|
|
|
|
arg_all * OUTPUT_SHOW_ALL |
|
|
|
|
(arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
|
|
|
|
colors_enabled() * OUTPUT_COLOR;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int show_logs(const LinkInfo *info) {
|
|
|
|
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (arg_lines == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to open journal: %m");
|
|
|
|
|
|
|
|
r = add_match_this_boot(j, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add boot matches: %m");
|
|
|
|
|
|
|
|
if (info) {
|
|
|
|
char m1[STRLEN("_KERNEL_DEVICE=n") + DECIMAL_STR_MAX(int)];
|
|
|
|
const char *m2, *m3;
|
|
|
|
|
|
|
|
/* kernel */
|
|
|
|
xsprintf(m1, "_KERNEL_DEVICE=n%i", info->ifindex);
|
|
|
|
/* networkd */
|
|
|
|
m2 = strjoina("INTERFACE=", info->name);
|
|
|
|
/* udevd */
|
|
|
|
m3 = strjoina("DEVICE=", info->name);
|
|
|
|
|
|
|
|
(void)(
|
|
|
|
(r = sd_journal_add_match(j, m1, 0)) ||
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, m2, 0)) ||
|
|
|
|
(r = sd_journal_add_disjunction(j)) ||
|
|
|
|
(r = sd_journal_add_match(j, m3, 0))
|
|
|
|
);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add link matches: %m");
|
|
|
|
} else {
|
|
|
|
r = add_matches_for_unit(j, "systemd-networkd.service");
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add unit matches: %m");
|
|
|
|
|
|
|
|
r = add_matches_for_unit(j, "systemd-networkd-wait-online.service");
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to add unit matches: %m");
|
|
|
|
}
|
|
|
|
|
|
|
|
return show_journal(
|
|
|
|
stdout,
|
|
|
|
j,
|
|
|
|
OUTPUT_SHORT,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
arg_lines,
|
|
|
|
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2014-12-12 18:57:15 +01:00
|
|
|
static int link_status_one(
|
2015-06-12 16:31:33 +02:00
|
|
|
sd_netlink *rtnl,
|
2014-12-15 20:07:34 +01:00
|
|
|
sd_hwdb *hwdb,
|
2016-02-19 19:18:12 +01:00
|
|
|
const LinkInfo *info) {
|
|
|
|
|
2020-03-24 18:08:07 +01:00
|
|
|
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL,
|
2020-04-22 14:50:27 +02:00
|
|
|
**pop3_server = NULL, **smtp_server = NULL, **lpr_server = NULL;
|
2015-08-30 03:18:33 +02:00
|
|
|
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
|
2014-09-08 14:00:34 +02:00
|
|
|
_cleanup_free_ char *t = NULL, *network = NULL;
|
2014-09-08 14:18:32 +02:00
|
|
|
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
|
2014-08-14 01:18:37 +02:00
|
|
|
const char *on_color_operational, *off_color_operational,
|
2019-05-22 18:43:21 +02:00
|
|
|
*on_color_setup, *off_color_setup;
|
2016-02-19 20:43:03 +01:00
|
|
|
_cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
|
2019-05-22 18:43:21 +02:00
|
|
|
_cleanup_(table_unrefp) Table *table = NULL;
|
|
|
|
TableCell *cell;
|
2016-02-19 19:18:12 +01:00
|
|
|
int r;
|
2014-08-12 15:19:30 +02:00
|
|
|
|
|
|
|
assert(rtnl);
|
2016-02-19 19:18:12 +01:00
|
|
|
assert(info);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
(void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
|
2019-10-23 11:10:32 +02:00
|
|
|
operational_state_to_color(info->name, operational_state, &on_color_operational, &off_color_operational);
|
2014-08-14 01:18:37 +02:00
|
|
|
|
2016-02-20 22:12:14 +01:00
|
|
|
r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
|
|
|
|
if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
|
|
|
|
setup_state = strdup("unmanaged");
|
2014-08-14 01:18:37 +02:00
|
|
|
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
(void) sd_network_link_get_dns(info->ifindex, &dns);
|
|
|
|
(void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
|
|
|
|
(void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
|
|
|
|
(void) sd_network_link_get_ntp(info->ifindex, &ntp);
|
2020-03-22 10:40:00 +01:00
|
|
|
(void) sd_network_link_get_sip(info->ifindex, &sip);
|
2020-03-24 18:08:07 +01:00
|
|
|
(void) sd_network_link_get_pop3_servers(info->ifindex, &pop3_server);
|
2020-03-23 10:42:00 +01:00
|
|
|
(void) sd_network_link_get_smtp_servers(info->ifindex, &smtp_server);
|
2020-04-22 14:50:27 +02:00
|
|
|
(void) sd_network_link_get_lpr_servers(info->ifindex, &lpr_server);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2019-10-23 17:02:18 +02:00
|
|
|
if (info->sd_device) {
|
|
|
|
(void) sd_device_get_property_value(info->sd_device, "ID_NET_LINK_FILE", &link);
|
|
|
|
(void) sd_device_get_property_value(info->sd_device, "ID_NET_DRIVER", &driver);
|
|
|
|
(void) sd_device_get_property_value(info->sd_device, "ID_PATH", &path);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2019-10-23 17:02:18 +02:00
|
|
|
if (sd_device_get_property_value(info->sd_device, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
|
|
|
|
(void) sd_device_get_property_value(info->sd_device, "ID_VENDOR", &vendor);
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2019-10-23 17:02:18 +02:00
|
|
|
if (sd_device_get_property_value(info->sd_device, "ID_MODEL_FROM_DATABASE", &model) < 0)
|
|
|
|
(void) sd_device_get_property_value(info->sd_device, "ID_MODEL", &model);
|
2014-08-12 15:19:30 +02:00
|
|
|
}
|
|
|
|
|
2019-10-23 17:02:18 +02:00
|
|
|
t = link_get_type_string(info->iftype, info->sd_device);
|
2014-12-12 19:11:35 +01:00
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_link_get_network_file(info->ifindex, &network);
|
2014-08-12 15:41:01 +02:00
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
|
|
|
|
(void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2019-07-16 13:32:51 +02:00
|
|
|
table = table_new("dot", "key", "value");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (!table)
|
2020-01-10 10:23:24 +01:00
|
|
|
return log_oom();
|
2019-05-22 18:43:21 +02:00
|
|
|
|
2020-01-10 04:12:00 +01:00
|
|
|
if (arg_full)
|
|
|
|
table_set_width(table, 0);
|
|
|
|
|
2019-06-03 09:04:16 +02:00
|
|
|
assert_se(cell = table_get_cell(table, 0, 0));
|
|
|
|
(void) table_set_ellipsize_percent(table, cell, 100);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 1));
|
|
|
|
(void) table_set_ellipsize_percent(table, cell, 100);
|
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
table_set_header(table, false);
|
|
|
|
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
|
|
|
|
TABLE_SET_COLOR, on_color_operational);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-06-03 09:04:16 +02:00
|
|
|
r = table_add_cell_stringf(table, &cell, "%i: %s", info->ifindex, info->name);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-06-03 09:04:16 +02:00
|
|
|
(void) table_set_align_percent(table, cell, 0);
|
2019-05-22 18:43:21 +02:00
|
|
|
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Link File:",
|
|
|
|
TABLE_SET_ALIGN_PERCENT, 100,
|
|
|
|
TABLE_STRING, strna(link),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Network File:",
|
|
|
|
TABLE_STRING, strna(network),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Type:",
|
|
|
|
TABLE_STRING, strna(t),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "State:");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
r = table_add_cell_stringf(table, NULL, "%s%s%s (%s%s%s)",
|
2019-06-29 19:54:35 +02:00
|
|
|
on_color_operational, strna(operational_state), off_color_operational,
|
|
|
|
on_color_setup, strna(setup_state), off_color_setup);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
|
2020-01-14 10:29:52 +01:00
|
|
|
r = dump_list(table, "Alternative Names:", info->alternative_names);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2019-12-15 20:27:27 +01:00
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
if (path) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Path:",
|
|
|
|
TABLE_STRING, path);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
|
|
|
if (driver) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Driver:",
|
|
|
|
TABLE_STRING, driver);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
|
|
|
if (vendor) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Vendor:",
|
|
|
|
TABLE_STRING, vendor);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
|
|
|
if (model) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Model:",
|
|
|
|
TABLE_STRING, model);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
if (info->has_mac_address) {
|
2014-12-12 18:50:06 +01:00
|
|
|
_cleanup_free_ char *description = NULL;
|
2014-08-15 13:18:50 +02:00
|
|
|
char ea[ETHER_ADDR_TO_STRING_MAX];
|
2014-12-12 18:50:06 +01:00
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) ieee_oui(hwdb, &info->mac_address, &description);
|
2014-12-12 18:50:06 +01:00
|
|
|
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "HW Address:");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
|
2019-06-29 19:54:35 +02:00
|
|
|
ether_addr_to_string(&info->mac_address, ea),
|
|
|
|
description ? " (" : "",
|
|
|
|
strempty(description),
|
|
|
|
description ? ")" : "");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2014-08-15 13:18:50 +02:00
|
|
|
}
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2019-01-07 12:16:20 +01:00
|
|
|
if (info->has_permanent_mac_address) {
|
|
|
|
_cleanup_free_ char *description = NULL;
|
|
|
|
char ea[ETHER_ADDR_TO_STRING_MAX];
|
|
|
|
|
|
|
|
(void) ieee_oui(hwdb, &info->permanent_mac_address, &description);
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "HW Permanent Address:");
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-01-07 12:16:20 +01:00
|
|
|
r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
|
|
|
|
ether_addr_to_string(&info->permanent_mac_address, ea),
|
|
|
|
description ? " (" : "",
|
|
|
|
strempty(description),
|
|
|
|
description ? ")" : "");
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-01-07 12:16:20 +01:00
|
|
|
}
|
|
|
|
|
2019-05-30 20:30:31 +02:00
|
|
|
if (info->mtu > 0) {
|
|
|
|
char min_str[DECIMAL_STR_MAX(uint32_t)], max_str[DECIMAL_STR_MAX(uint32_t)];
|
|
|
|
|
|
|
|
xsprintf(min_str, "%" PRIu32, info->min_mtu);
|
|
|
|
xsprintf(max_str, "%" PRIu32, info->max_mtu);
|
|
|
|
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "MTU:");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-30 20:30:31 +02:00
|
|
|
r = table_add_cell_stringf(table, NULL, "%" PRIu32 "%s%s%s%s%s%s%s",
|
|
|
|
info->mtu,
|
|
|
|
info->min_mtu > 0 || info->max_mtu > 0 ? " (" : "",
|
2019-05-31 10:56:45 +02:00
|
|
|
info->min_mtu > 0 ? "min: " : "",
|
2019-05-30 20:30:31 +02:00
|
|
|
info->min_mtu > 0 ? min_str : "",
|
|
|
|
info->min_mtu > 0 && info->max_mtu > 0 ? ", " : "",
|
2019-05-31 10:56:45 +02:00
|
|
|
info->max_mtu > 0 ? "max: " : "",
|
2019-05-30 20:30:31 +02:00
|
|
|
info->max_mtu > 0 ? max_str : "",
|
|
|
|
info->min_mtu > 0 || info->max_mtu > 0 ? ")" : "");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-03-13 10:54:35 +01:00
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->qdisc) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "QDisc:",
|
|
|
|
TABLE_STRING, info->qdisc);
|
|
|
|
if (r < 0)
|
2020-03-14 10:09:48 +01:00
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->master > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Master:",
|
|
|
|
TABLE_IFINDEX, info->master);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
2015-08-26 19:19:32 +02:00
|
|
|
|
2020-03-18 13:42:27 +01:00
|
|
|
if (info->has_ipv6_address_generation_mode) {
|
|
|
|
static const struct {
|
|
|
|
const char *mode;
|
|
|
|
} mode_table[] = {
|
|
|
|
{ "eui64" },
|
|
|
|
{ "none" },
|
|
|
|
{ "stable-privacy" },
|
|
|
|
{ "random" },
|
|
|
|
};
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "IPv6 Address Generation Mode:",
|
|
|
|
TABLE_STRING, mode_table[info->addr_gen_mode]);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
if (streq_ptr(info->netdev_kind, "bridge")) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Forward Delay:",
|
|
|
|
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->forward_delay),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Hello Time:",
|
|
|
|
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->hello_time),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Max Age:",
|
|
|
|
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->max_age),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Ageing Time:",
|
|
|
|
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->ageing_time),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Priority:",
|
|
|
|
TABLE_UINT16, info->priority,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "STP:",
|
|
|
|
TABLE_BOOLEAN, info->stp_state > 0,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Multicast IGMP Version:",
|
2020-03-22 14:27:30 +01:00
|
|
|
TABLE_UINT8, info->mcast_igmp_version,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Cost:",
|
|
|
|
TABLE_UINT32, info->cost);
|
2019-07-25 19:09:34 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-07-25 19:09:34 +02:00
|
|
|
|
2020-03-22 14:27:30 +01:00
|
|
|
if (info->port_state <= BR_STATE_BLOCKING) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Port State:",
|
2020-03-24 12:23:35 +01:00
|
|
|
TABLE_STRING, bridge_state_to_string(info->port_state));
|
2020-03-22 14:27:30 +01:00
|
|
|
}
|
2020-03-18 08:50:15 +01:00
|
|
|
} else if (streq_ptr(info->netdev_kind, "bond")) {
|
|
|
|
static const struct {
|
|
|
|
const char *mode;
|
|
|
|
} mode_table[] = {
|
|
|
|
{ "balance-rr" },
|
|
|
|
{ "active-backup" },
|
|
|
|
{ "balance-xor" },
|
|
|
|
{ "broadcast" },
|
|
|
|
{ "802.3ad" },
|
|
|
|
{ "balance-tlb" },
|
|
|
|
{ "balance-alb" },
|
|
|
|
};
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Mode:",
|
|
|
|
TABLE_STRING, mode_table[info->mode],
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Miimon:",
|
|
|
|
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->miimon),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Updelay:",
|
|
|
|
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->updelay),
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Downdelay:",
|
|
|
|
TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->downdelay));
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
} else if (streq_ptr(info->netdev_kind, "vxlan")) {
|
2020-03-23 16:24:04 +01:00
|
|
|
char ttl[CONST_MAX(STRLEN("auto") + 1, DECIMAL_STR_MAX(uint8_t))];
|
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
if (info->vxlan_info.vni > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "VNI:",
|
|
|
|
TABLE_UINT32, info->vxlan_info.vni);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-07-25 19:09:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IN_SET(info->vxlan_info.group_family, AF_INET, AF_INET6)) {
|
2020-04-10 15:50:23 +02:00
|
|
|
const char *p;
|
|
|
|
|
|
|
|
r = in_addr_is_multicast(info->vxlan_info.group_family, &info->vxlan_info.group);
|
|
|
|
if (r <= 0)
|
|
|
|
p = "Remote:";
|
|
|
|
else
|
|
|
|
p = "Group:";
|
|
|
|
|
2019-07-25 19:09:34 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
2020-04-10 15:50:23 +02:00
|
|
|
TABLE_STRING, p,
|
2019-07-25 19:09:34 +02:00
|
|
|
info->vxlan_info.group_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
|
|
|
|
&info->vxlan_info.group);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-07-25 19:09:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IN_SET(info->vxlan_info.local_family, AF_INET, AF_INET6)) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Local:",
|
|
|
|
info->vxlan_info.local_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
|
|
|
|
&info->vxlan_info.local);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-07-25 19:09:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->vxlan_info.dest_port > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Destination Port:",
|
|
|
|
TABLE_UINT16, be16toh(info->vxlan_info.dest_port));
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-07-25 19:09:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->vxlan_info.link > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Underlying Device:",
|
|
|
|
TABLE_IFINDEX, info->vxlan_info.link);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-07-25 19:09:34 +02:00
|
|
|
}
|
2020-03-23 16:24:04 +01:00
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Learning:",
|
|
|
|
TABLE_BOOLEAN, info->vxlan_info.learning);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "RSC:",
|
|
|
|
TABLE_BOOLEAN, info->vxlan_info.rsc);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "L3MISS:",
|
|
|
|
TABLE_BOOLEAN, info->vxlan_info.l3miss);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "L2MISS:",
|
|
|
|
TABLE_BOOLEAN, info->vxlan_info.l2miss);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
if (info->vxlan_info.tos > 1) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "TOS:",
|
|
|
|
TABLE_UINT8, info->vxlan_info.tos);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->vxlan_info.ttl > 0)
|
|
|
|
xsprintf(ttl, "%" PRIu8, info->vxlan_info.ttl);
|
|
|
|
else
|
|
|
|
strcpy(ttl, "auto");
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "TTL:",
|
|
|
|
TABLE_STRING, ttl);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
2020-03-16 14:36:26 +01:00
|
|
|
} else if (streq_ptr(info->netdev_kind, "vlan") && info->vlan_id > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "VLan Id:",
|
|
|
|
TABLE_UINT16, info->vlan_id);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
2020-03-18 05:21:41 +01:00
|
|
|
} else if (STRPTR_IN_SET(info->netdev_kind, "ipip", "sit", "gre", "gretap", "erspan", "vti")) {
|
2020-03-17 06:08:05 +01:00
|
|
|
if (!in_addr_is_null(AF_INET, &info->local)) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Local:",
|
|
|
|
TABLE_IN_ADDR, &info->local);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in_addr_is_null(AF_INET, &info->remote)) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Remote:",
|
|
|
|
TABLE_IN_ADDR, &info->remote);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
2020-03-18 05:21:41 +01:00
|
|
|
} else if (STRPTR_IN_SET(info->netdev_kind, "ip6gre", "ip6gretap", "ip6erspan", "vti6")) {
|
2020-03-18 04:27:09 +01:00
|
|
|
if (!in_addr_is_null(AF_INET6, &info->local)) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Local:",
|
|
|
|
TABLE_IN6_ADDR, &info->local);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!in_addr_is_null(AF_INET6, &info->remote)) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Remote:",
|
|
|
|
TABLE_IN6_ADDR, &info->remote);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
2020-03-17 10:56:57 +01:00
|
|
|
} else if (streq_ptr(info->netdev_kind, "geneve")) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "VNI:",
|
|
|
|
TABLE_UINT32, info->vni);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
if (info->has_tunnel_ipv4 && !in_addr_is_null(AF_INET, &info->remote)) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Remote:",
|
|
|
|
TABLE_IN_ADDR, &info->remote);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
} else if (!in_addr_is_null(AF_INET6, &info->remote)) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Remote:",
|
|
|
|
TABLE_IN6_ADDR, &info->remote);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->ttl > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "TTL:",
|
|
|
|
TABLE_UINT8, info->ttl);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (info->tos > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "TOS:",
|
|
|
|
TABLE_UINT8, info->tos);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Port:",
|
|
|
|
TABLE_UINT16, info->tunnel_port);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
2020-03-25 14:52:52 +01:00
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Inherit:",
|
|
|
|
TABLE_STRING, geneve_df_to_string(info->inherit));
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
if (info->df > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "IPDoNotFragment:",
|
|
|
|
TABLE_UINT8, info->df);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "UDPChecksum:",
|
|
|
|
TABLE_BOOLEAN, info->csum);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "UDP6ZeroChecksumTx:",
|
|
|
|
TABLE_BOOLEAN, info->csum6_tx);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "UDP6ZeroChecksumRx:",
|
|
|
|
TABLE_BOOLEAN, info->csum6_rx);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
if (info->label > 0) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "FlowLabel:",
|
|
|
|
TABLE_UINT32, info->label);
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
|
|
|
}
|
2020-03-19 05:24:49 +01:00
|
|
|
} else if (STRPTR_IN_SET(info->netdev_kind, "macvlan", "macvtap")) {
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Mode:",
|
|
|
|
TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode));
|
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
2019-07-25 19:09:34 +02:00
|
|
|
}
|
|
|
|
|
2019-10-23 17:05:33 +02:00
|
|
|
if (info->has_wlan_link_info) {
|
|
|
|
_cleanup_free_ char *esc = NULL;
|
|
|
|
char buf[ETHER_ADDR_TO_STRING_MAX];
|
|
|
|
|
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "WiFi access point:");
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-10-23 17:05:33 +02:00
|
|
|
|
|
|
|
if (info->ssid)
|
|
|
|
esc = cescape(info->ssid);
|
|
|
|
|
|
|
|
r = table_add_cell_stringf(table, NULL, "%s (%s)",
|
|
|
|
strnull(esc),
|
|
|
|
ether_addr_to_string(&info->bssid, buf));
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-10-23 17:05:33 +02:00
|
|
|
}
|
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
if (info->has_bitrates) {
|
2019-06-19 15:18:54 +02:00
|
|
|
char tx[FORMAT_BYTES_MAX], rx[FORMAT_BYTES_MAX];
|
2019-05-25 17:22:05 +02:00
|
|
|
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Bit Rate (Tx/Rx):");
|
2019-05-25 17:22:05 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-06-19 15:18:54 +02:00
|
|
|
r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
|
|
|
|
format_bytes_full(tx, sizeof tx, info->tx_bitrate, 0),
|
|
|
|
format_bytes_full(rx, sizeof rx, info->rx_bitrate, 0));
|
2019-05-25 17:22:05 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-25 17:22:05 +02:00
|
|
|
}
|
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
if (info->has_tx_queues || info->has_rx_queues) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Queue Length (Tx/Rx):");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
r = table_add_cell_stringf(table, NULL, "%" PRIu32 "/%" PRIu32, info->tx_queues, info->rx_queues);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
2015-02-17 13:06:57 +01:00
|
|
|
|
2019-06-17 09:12:06 +02:00
|
|
|
if (info->has_ethtool_link_info) {
|
|
|
|
const char *duplex = duplex_to_string(info->duplex);
|
|
|
|
const char *port = port_to_string(info->port);
|
|
|
|
|
|
|
|
if (IN_SET(info->autonegotiation, AUTONEG_DISABLE, AUTONEG_ENABLE)) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Auto negotiation:",
|
|
|
|
TABLE_BOOLEAN, info->autonegotiation == AUTONEG_ENABLE);
|
2019-06-17 09:12:06 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-06-17 09:12:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (info->speed > 0) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Speed:",
|
2020-01-21 12:06:40 +01:00
|
|
|
TABLE_BPS, info->speed);
|
2019-06-17 09:12:06 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-06-17 09:12:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (duplex) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Duplex:",
|
|
|
|
TABLE_STRING, duplex);
|
2019-06-17 09:12:06 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-06-17 09:12:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (port) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Port:",
|
|
|
|
TABLE_STRING, port);
|
2019-06-17 09:12:06 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-06-17 09:12:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
r = dump_addresses(rtnl, table, info->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_gateways(rtnl, hwdb, table, info->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "DNS:", dns);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "Search Domains:", search_domains);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "Route Domains:", route_domains);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "NTP:", ntp);
|
2020-03-22 10:40:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "SIP:", sip);
|
2020-03-24 18:08:07 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "POP3 servers:", pop3_server);
|
2020-03-23 10:42:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "SMTP servers:", smtp_server);
|
2020-04-22 14:50:27 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_list(table, "LPR servers:", lpr_server);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_ifindexes(table, "Carrier Bound To:", carrier_bound_to);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_ifindexes(table, "Carrier Bound By:", carrier_bound_by);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2014-08-12 15:19:30 +02:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
(void) sd_network_link_get_timezone(info->ifindex, &tz);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (tz) {
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_EMPTY,
|
|
|
|
TABLE_STRING, "Time Zone:",
|
|
|
|
TABLE_STRING, tz);
|
2019-05-22 18:43:21 +02:00
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2019-05-22 18:43:21 +02:00
|
|
|
}
|
2015-08-26 19:19:32 +02:00
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-19 19:50:14 +01:00
|
|
|
|
2019-05-24 17:37:48 +02:00
|
|
|
r = dump_statistics(table, info);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
2020-01-07 03:32:03 +01:00
|
|
|
r = table_print(table, NULL);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return log_error_errno(r, "Failed to print table: %m");
|
2020-01-07 03:32:03 +01:00
|
|
|
|
|
|
|
return show_logs(info);
|
2014-08-12 15:19:30 +02:00
|
|
|
}
|
|
|
|
|
2016-02-19 18:20:40 +01:00
|
|
|
static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
|
|
|
|
_cleanup_free_ char *operational_state = NULL;
|
|
|
|
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
|
|
|
|
const char *on_color_operational, *off_color_operational;
|
2019-05-22 18:43:21 +02:00
|
|
|
_cleanup_(table_unrefp) Table *table = NULL;
|
|
|
|
TableCell *cell;
|
|
|
|
int r;
|
2016-02-19 18:20:40 +01:00
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_get_operational_state(&operational_state);
|
2019-10-23 11:10:32 +02:00
|
|
|
operational_state_to_color(NULL, operational_state, &on_color_operational, &off_color_operational);
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2019-07-16 13:32:51 +02:00
|
|
|
table = table_new("dot", "key", "value");
|
2019-05-22 18:43:21 +02:00
|
|
|
if (!table)
|
2020-01-10 10:23:24 +01:00
|
|
|
return log_oom();
|
2019-05-22 18:43:21 +02:00
|
|
|
|
2020-01-10 04:12:00 +01:00
|
|
|
if (arg_full)
|
|
|
|
table_set_width(table, 0);
|
|
|
|
|
2019-06-03 09:04:16 +02:00
|
|
|
assert_se(cell = table_get_cell(table, 0, 0));
|
|
|
|
(void) table_set_ellipsize_percent(table, cell, 100);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 1));
|
|
|
|
(void) table_set_align_percent(table, cell, 100);
|
|
|
|
(void) table_set_ellipsize_percent(table, cell, 100);
|
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
table_set_header(table, false);
|
|
|
|
|
2019-07-28 06:07:19 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
|
|
|
|
TABLE_SET_COLOR, on_color_operational,
|
|
|
|
TABLE_STRING, "State:",
|
|
|
|
TABLE_STRING, strna(operational_state),
|
|
|
|
TABLE_SET_COLOR, on_color_operational);
|
2020-01-10 10:23:24 +01:00
|
|
|
if (r < 0)
|
|
|
|
return table_log_add_error(r);
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2019-05-22 18:43:21 +02:00
|
|
|
r = dump_addresses(rtnl, table, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
r = dump_gateways(rtnl, hwdb, table, 0);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_get_dns(&dns);
|
2019-05-22 18:43:21 +02:00
|
|
|
r = dump_list(table, "DNS:", dns);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_get_search_domains(&search_domains);
|
2019-05-22 18:43:21 +02:00
|
|
|
r = dump_list(table, "Search Domains:", search_domains);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_get_route_domains(&route_domains);
|
2019-05-22 18:43:21 +02:00
|
|
|
r = dump_list(table, "Route Domains:", route_domains);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2016-02-20 21:34:38 +01:00
|
|
|
(void) sd_network_get_ntp(&ntp);
|
2019-05-22 18:43:21 +02:00
|
|
|
r = dump_list(table, "NTP:", ntp);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2020-01-07 03:32:03 +01:00
|
|
|
r = table_print(table, NULL);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return log_error_errno(r, "Failed to print table: %m");
|
2020-01-07 03:32:03 +01:00
|
|
|
|
|
|
|
return show_logs(NULL);
|
2016-02-19 18:20:40 +01:00
|
|
|
}
|
|
|
|
|
2014-12-19 03:16:45 +01:00
|
|
|
static int link_status(int argc, char *argv[], void *userdata) {
|
2019-05-25 17:22:05 +02:00
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2016-02-19 19:18:12 +01:00
|
|
|
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
|
2019-10-23 17:02:18 +02:00
|
|
|
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
|
2016-02-19 19:18:12 +01:00
|
|
|
int r, c, i;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
2016-02-19 18:20:40 +01:00
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
r = sd_bus_open_system(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect system bus: %m");
|
|
|
|
|
2015-06-12 16:31:33 +02:00
|
|
|
r = sd_netlink_open(&rtnl);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
2014-08-12 16:19:37 +02:00
|
|
|
|
2014-12-15 20:07:34 +01:00
|
|
|
r = sd_hwdb_new(&hwdb);
|
|
|
|
if (r < 0)
|
|
|
|
log_debug_errno(r, "Failed to open hardware database: %m");
|
2014-12-12 18:57:15 +01:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
if (arg_all)
|
2019-05-25 17:22:05 +02:00
|
|
|
c = acquire_link_info(bus, rtnl, NULL, &links);
|
2016-02-19 19:18:12 +01:00
|
|
|
else if (argc <= 1)
|
2016-02-19 18:20:40 +01:00
|
|
|
return system_status(rtnl, hwdb);
|
2016-02-19 19:18:12 +01:00
|
|
|
else
|
2019-05-25 17:22:05 +02:00
|
|
|
c = acquire_link_info(bus, rtnl, argv + 1, &links);
|
2016-02-19 19:18:12 +01:00
|
|
|
if (c < 0)
|
|
|
|
return c;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
for (i = 0; i < c; i++) {
|
|
|
|
if (i > 0)
|
|
|
|
fputc('\n', stdout);
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
link_status_one(rtnl, hwdb, links + i);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
static char *lldp_capabilities_to_string(uint16_t x) {
|
|
|
|
static const char characters[] = {
|
|
|
|
'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
|
|
|
|
};
|
|
|
|
char *ret;
|
|
|
|
unsigned i;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
ret = new(char, ELEMENTSOF(characters) + 1);
|
|
|
|
if (!ret)
|
2014-12-11 05:29:55 +01:00
|
|
|
return NULL;
|
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
for (i = 0; i < ELEMENTSOF(characters); i++)
|
|
|
|
ret[i] = (x & (1U << i)) ? characters[i] : '.';
|
2014-12-11 05:29:55 +01:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
ret[i] = 0;
|
|
|
|
return ret;
|
2014-12-11 05:29:55 +01:00
|
|
|
}
|
|
|
|
|
2016-02-23 05:23:56 +01:00
|
|
|
static void lldp_capabilities_legend(uint16_t x) {
|
|
|
|
unsigned w, i, cols = columns();
|
2016-02-23 20:25:48 +01:00
|
|
|
static const char* const table[] = {
|
2016-02-23 05:23:56 +01:00
|
|
|
"o - Other",
|
|
|
|
"p - Repeater",
|
|
|
|
"b - Bridge",
|
|
|
|
"w - WLAN Access Point",
|
|
|
|
"r - Router",
|
|
|
|
"t - Telephone",
|
|
|
|
"d - DOCSIS cable device",
|
|
|
|
"a - Station",
|
|
|
|
"c - Customer VLAN",
|
|
|
|
"s - Service VLAN",
|
|
|
|
"m - Two-port MAC Relay (TPMR)",
|
|
|
|
};
|
|
|
|
|
|
|
|
if (x == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
printf("\nCapability Flags:\n");
|
|
|
|
for (w = 0, i = 0; i < ELEMENTSOF(table); i++)
|
|
|
|
if (x & (1U << i) || arg_all) {
|
|
|
|
bool newline;
|
|
|
|
|
|
|
|
newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols;
|
|
|
|
if (newline)
|
|
|
|
w = 0;
|
|
|
|
w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]);
|
|
|
|
}
|
|
|
|
puts("");
|
|
|
|
}
|
|
|
|
|
2014-12-11 05:29:55 +01:00
|
|
|
static int link_lldp_status(int argc, char *argv[], void *userdata) {
|
2016-02-19 19:18:12 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2019-10-23 17:02:18 +02:00
|
|
|
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
|
2019-05-22 22:13:13 +02:00
|
|
|
_cleanup_(table_unrefp) Table *table = NULL;
|
2016-02-19 19:18:12 +01:00
|
|
|
int i, r, c, m = 0;
|
2016-02-23 05:23:56 +01:00
|
|
|
uint16_t all = 0;
|
2019-05-22 22:13:13 +02:00
|
|
|
TableCell *cell;
|
2016-02-19 19:18:12 +01:00
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2019-05-25 17:22:05 +02:00
|
|
|
c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
|
2014-12-11 05:29:55 +01:00
|
|
|
if (c < 0)
|
2016-02-19 18:26:18 +01:00
|
|
|
return c;
|
|
|
|
|
2018-11-11 12:56:29 +01:00
|
|
|
(void) pager_open(arg_pager_flags);
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2019-07-16 13:32:51 +02:00
|
|
|
table = table_new("link",
|
|
|
|
"chassis id",
|
|
|
|
"system name",
|
|
|
|
"caps",
|
|
|
|
"port id",
|
|
|
|
"port description");
|
2019-05-22 22:13:13 +02:00
|
|
|
if (!table)
|
2020-01-10 10:23:24 +01:00
|
|
|
return log_oom();
|
2019-05-22 22:13:13 +02:00
|
|
|
|
2020-01-10 04:12:00 +01:00
|
|
|
if (arg_full)
|
|
|
|
table_set_width(table, 0);
|
|
|
|
|
2019-05-22 22:13:13 +02:00
|
|
|
table_set_header(table, arg_legend);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 0));
|
|
|
|
table_set_minimum_width(table, cell, 16);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 1));
|
|
|
|
table_set_minimum_width(table, cell, 17);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 2));
|
|
|
|
table_set_minimum_width(table, cell, 16);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 3));
|
|
|
|
table_set_minimum_width(table, cell, 11);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 4));
|
|
|
|
table_set_minimum_width(table, cell, 17);
|
|
|
|
|
|
|
|
assert_se(cell = table_get_cell(table, 0, 5));
|
|
|
|
table_set_minimum_width(table, cell, 16);
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2016-02-19 19:18:12 +01:00
|
|
|
for (i = 0; i < c; i++) {
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2016-02-19 19:50:14 +01:00
|
|
|
r = open_lldp_neighbors(links[i].ifindex, &f);
|
|
|
|
if (r == -ENOENT)
|
|
|
|
continue;
|
|
|
|
if (r < 0) {
|
|
|
|
log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
continue;
|
|
|
|
}
|
2014-12-11 05:29:55 +01:00
|
|
|
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
for (;;) {
|
2019-05-30 13:58:33 +02:00
|
|
|
_cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL, *capabilities = NULL;
|
|
|
|
const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL;
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
|
|
|
uint16_t cc;
|
2014-12-11 05:29:55 +01:00
|
|
|
|
2016-02-19 19:50:14 +01:00
|
|
|
r = next_lldp_neighbor(f, &n);
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
if (r < 0) {
|
2016-02-19 19:50:14 +01:00
|
|
|
log_warning_errno(r, "Failed to read neighbor data: %m");
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
break;
|
2014-12-11 05:29:55 +01:00
|
|
|
}
|
2016-02-19 19:50:14 +01:00
|
|
|
if (r == 0)
|
|
|
|
break;
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
|
|
|
|
(void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
|
|
|
|
(void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
|
|
|
|
(void) sd_lldp_neighbor_get_system_name(n, &system_name);
|
|
|
|
(void) sd_lldp_neighbor_get_port_description(n, &port_description);
|
|
|
|
|
2016-02-21 14:31:51 +01:00
|
|
|
if (chassis_id) {
|
|
|
|
cid = ellipsize(chassis_id, 17, 100);
|
|
|
|
if (cid)
|
|
|
|
chassis_id = cid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port_id) {
|
|
|
|
pid = ellipsize(port_id, 17, 100);
|
|
|
|
if (pid)
|
|
|
|
port_id = pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (system_name) {
|
|
|
|
sname = ellipsize(system_name, 16, 100);
|
|
|
|
if (sname)
|
|
|
|
system_name = sname;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (port_description) {
|
|
|
|
pdesc = ellipsize(port_description, 16, 100);
|
|
|
|
if (pdesc)
|
|
|
|
port_description = pdesc;
|
|
|
|
}
|
|
|
|
|
2016-02-23 05:23:56 +01:00
|
|
|
if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
capabilities = lldp_capabilities_to_string(cc);
|
2016-02-23 05:23:56 +01:00
|
|
|
all |= cc;
|
|
|
|
}
|
sd-lldp: rework sd-lldp API
This reworks the sd-lldp substantially, simplifying things on one hand, and
extending the logic a bit on the other.
Specifically:
- Besides the sd_lldp object only one other object is maintained now,
sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for
maintainging info about peers in the database. Separation between packet, TLV
and chassis data is not maintained anymore. This should be a major
simplification.
- The sd-lldp API has been extended so that a couple of per-neighbor fields may
be queried directly, without iterating through the object. Other fields that
may appear multiple times, OTOH have to be iterated through.
- The maximum number of entries in the neighbor database is now configurable
during runtime.
- The generation of callbacks from sd_lldp objects is more restricted:
callbacks are only invoked when actual data changed.
- The TTL information is now hooked with a timer event, so that removals from
the neighbor database due to TTLs now result in a callback event.
- Querying LLDP neighbor database will now return a strictly ordered array, to
guarantee stability.
- A "capabilities" mask may now be configured, that selects what type of LLDP
neighbor data is collected. This may be used to restrict collection of LLDP
info about routers instead of all neighbors. This is now exposed via
networkd's LLDP= setting.
- sd-lldp's API to serialize the collected data to text files has been removed.
Instead, there's now an API to extract the raw binary data from LLDP neighbor
objects, as well as one to convert this raw binary data back to an LLDP
neighbor object. networkd will save this raw binary data to /run now, and the
client side can simply parse the information.
- support for parsing the more exotic TLVs has been removed, since we are not
using that. Instead there are now APIs to extract the raw data from TLVs.
Given how easy it is to parse the TLVs clients should do so now directly
instead of relying on our APIs for that.
- A lot of the APIs that parse out LLDP strings have been simplified so that
they actually return strings, instead of char arrays with a length. To deal
with possibly dangerous characters the strings are escaped if needed.
- APIs to extract and format the chassis and port IDs as strings has been
added.
- lldp.h has been simplified a lot. The enums are anonymous now, since they
were never used as enums, but simply as constants. Most definitions we don't
actually use ourselves have eben removed.
2016-02-19 17:58:52 +01:00
|
|
|
|
2019-05-22 22:13:13 +02:00
|
|
|
r = table_add_many(table,
|
|
|
|
TABLE_STRING, links[i].name,
|
|
|
|
TABLE_STRING, strna(chassis_id),
|
|
|
|
TABLE_STRING, strna(system_name),
|
|
|
|
TABLE_STRING, strna(capabilities),
|
|
|
|
TABLE_STRING, strna(port_id),
|
|
|
|
TABLE_STRING, strna(port_description));
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return table_log_add_error(r);
|
2016-02-19 19:18:12 +01:00
|
|
|
|
|
|
|
m++;
|
2014-12-11 05:29:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-22 22:13:13 +02:00
|
|
|
r = table_print(table, NULL);
|
|
|
|
if (r < 0)
|
2020-01-10 10:23:24 +01:00
|
|
|
return log_error_errno(r, "Failed to print table: %m");
|
2019-05-22 22:13:13 +02:00
|
|
|
|
2016-02-23 05:23:56 +01:00
|
|
|
if (arg_legend) {
|
|
|
|
lldp_capabilities_legend(all);
|
|
|
|
printf("\n%i neighbors listed.\n", m);
|
|
|
|
}
|
2014-12-11 05:29:55 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-22 11:46:41 +02:00
|
|
|
static int link_delete_send_message(sd_netlink *rtnl, int index) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &req, RTM_DELLINK, index);
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, req, 0, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-24 07:10:53 +01:00
|
|
|
static int link_up_down_send_message(sd_netlink *rtnl, char *command, int index) {
|
|
|
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(rtnl);
|
|
|
|
|
|
|
|
r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, index);
|
|
|
|
if (r < 0)
|
|
|
|
return rtnl_log_create_error(r);
|
|
|
|
|
|
|
|
if (streq(command, "up"))
|
|
|
|
r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
|
|
|
|
else
|
|
|
|
r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Could not set link flags: %m");
|
|
|
|
|
|
|
|
r = sd_netlink_call(rtnl, req, 0, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_up_down(int argc, char *argv[], void *userdata) {
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
|
|
|
_cleanup_set_free_ Set *indexes = NULL;
|
|
|
|
int index, r, i;
|
|
|
|
Iterator j;
|
|
|
|
void *p;
|
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
indexes = set_new(NULL);
|
|
|
|
if (!indexes)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
index = resolve_interface_or_warn(&rtnl, argv[i]);
|
|
|
|
if (index < 0)
|
|
|
|
return index;
|
|
|
|
|
|
|
|
r = set_put(indexes, INT_TO_PTR(index));
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
SET_FOREACH(p, indexes, j) {
|
|
|
|
index = PTR_TO_INT(p);
|
|
|
|
r = link_up_down_send_message(rtnl, argv[0], index);
|
|
|
|
if (r < 0) {
|
|
|
|
char ifname[IF_NAMESIZE + 1];
|
|
|
|
|
|
|
|
return log_error_errno(r, "Failed to %s interface %s: %m",
|
|
|
|
argv[1], format_ifname_full(index, ifname, FORMAT_IFNAME_IFINDEX));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-05-22 11:46:41 +02:00
|
|
|
static int link_delete(int argc, char *argv[], void *userdata) {
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
|
|
|
_cleanup_set_free_ Set *indexes = NULL;
|
|
|
|
int index, r, i;
|
|
|
|
Iterator j;
|
2019-06-04 07:00:51 +02:00
|
|
|
void *p;
|
2019-05-22 11:46:41 +02:00
|
|
|
|
|
|
|
r = sd_netlink_open(&rtnl);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect to netlink: %m");
|
|
|
|
|
|
|
|
indexes = set_new(NULL);
|
|
|
|
if (!indexes)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
2020-01-11 11:21:01 +01:00
|
|
|
index = resolve_interface_or_warn(&rtnl, argv[i]);
|
2019-12-18 14:18:34 +01:00
|
|
|
if (index < 0)
|
|
|
|
return index;
|
2019-05-22 11:46:41 +02:00
|
|
|
|
|
|
|
r = set_put(indexes, INT_TO_PTR(index));
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
2019-06-04 07:00:51 +02:00
|
|
|
SET_FOREACH(p, indexes, j) {
|
2019-09-08 11:32:54 +02:00
|
|
|
index = PTR_TO_INT(p);
|
|
|
|
r = link_delete_send_message(rtnl, index);
|
2019-05-22 11:46:41 +02:00
|
|
|
if (r < 0) {
|
2019-05-29 07:18:41 +02:00
|
|
|
char ifname[IF_NAMESIZE + 1];
|
|
|
|
|
2019-09-08 12:45:58 +02:00
|
|
|
return log_error_errno(r, "Failed to delete interface %s: %m",
|
|
|
|
format_ifname_full(index, ifname, FORMAT_IFNAME_IFINDEX));
|
2019-05-22 11:46:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2019-07-18 15:26:49 +02:00
|
|
|
static int link_renew_one(sd_bus *bus, int index, const char *name) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
int r;
|
|
|
|
|
2020-05-03 08:14:23 +02:00
|
|
|
r = bus_call_method(bus, bus_network_mgr, "RenewLink", &error, NULL, "i", index);
|
2019-07-18 15:26:49 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to renew dynamic configuration of interface %s: %s",
|
|
|
|
name, bus_error_message(&error, r));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_renew(int argc, char *argv[], void *userdata) {
|
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
2019-12-17 13:07:46 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2019-07-18 15:26:49 +02:00
|
|
|
int index, i, k = 0, r;
|
|
|
|
|
|
|
|
r = sd_bus_open_system(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect system bus: %m");
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
2020-01-11 11:21:01 +01:00
|
|
|
index = resolve_interface_or_warn(&rtnl, argv[i]);
|
2019-12-18 14:18:34 +01:00
|
|
|
if (index < 0)
|
|
|
|
return index;
|
2019-07-18 15:26:49 +02:00
|
|
|
|
|
|
|
r = link_renew_one(bus, index, argv[i]);
|
|
|
|
if (r < 0 && k >= 0)
|
|
|
|
k = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
2020-02-19 07:42:26 +01:00
|
|
|
static int link_force_renew_one(sd_bus *bus, int index, const char *name) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
int r;
|
|
|
|
|
2020-05-03 08:14:23 +02:00
|
|
|
r = bus_call_method(bus, bus_network_mgr, "ForceRenewLink", &error, NULL, "i", index);
|
2020-02-19 07:42:26 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to force renew dynamic configuration of interface %s: %s",
|
|
|
|
name, bus_error_message(&error, r));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int link_force_renew(int argc, char *argv[], void *userdata) {
|
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
|
|
|
int index, i, k = 0, r;
|
|
|
|
|
|
|
|
r = sd_bus_open_system(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect system bus: %m");
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
|
|
index = resolve_interface_or_warn(&rtnl, argv[i]);
|
|
|
|
if (index < 0)
|
|
|
|
return index;
|
|
|
|
|
|
|
|
r = link_force_renew_one(bus, index, argv[i]);
|
|
|
|
if (r < 0 && k >= 0)
|
|
|
|
k = r;
|
|
|
|
}
|
|
|
|
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
2019-10-23 15:24:42 +02:00
|
|
|
static int verb_reload(int argc, char *argv[], void *userdata) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = sd_bus_open_system(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect system bus: %m");
|
|
|
|
|
2020-05-03 08:14:23 +02:00
|
|
|
r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL);
|
2019-10-23 15:24:42 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to reload network settings: %m");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-23 15:36:04 +02:00
|
|
|
static int verb_reconfigure(int argc, char *argv[], void *userdata) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
2019-12-17 13:07:46 +01:00
|
|
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
2019-10-23 15:36:04 +02:00
|
|
|
_cleanup_set_free_ Set *indexes = NULL;
|
|
|
|
int index, i, r;
|
|
|
|
Iterator j;
|
|
|
|
void *p;
|
|
|
|
|
|
|
|
r = sd_bus_open_system(&bus);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to connect system bus: %m");
|
|
|
|
|
|
|
|
indexes = set_new(NULL);
|
|
|
|
if (!indexes)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
2020-01-11 11:21:01 +01:00
|
|
|
index = resolve_interface_or_warn(&rtnl, argv[i]);
|
2019-12-18 14:18:34 +01:00
|
|
|
if (index < 0)
|
|
|
|
return index;
|
2019-10-23 15:36:04 +02:00
|
|
|
|
|
|
|
r = set_put(indexes, INT_TO_PTR(index));
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
}
|
|
|
|
|
|
|
|
SET_FOREACH(p, indexes, j) {
|
|
|
|
index = PTR_TO_INT(p);
|
2020-05-03 08:14:23 +02:00
|
|
|
r = bus_call_method(bus, bus_network_mgr, "ReconfigureLink", &error, NULL, "i", index);
|
2019-10-23 15:36:04 +02:00
|
|
|
if (r < 0) {
|
|
|
|
char ifname[IF_NAMESIZE + 1];
|
|
|
|
|
2020-01-11 12:36:21 +01:00
|
|
|
return log_error_errno(r, "Failed to reconfigure network interface %s: %m",
|
|
|
|
format_ifname_full(index, ifname, FORMAT_IFNAME_IFINDEX));
|
2019-10-23 15:36:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-08-09 10:32:31 +02:00
|
|
|
static int help(void) {
|
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = terminal_urlify_man("networkctl", "1", &link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
2019-11-15 18:38:44 +01:00
|
|
|
printf("%s [OPTIONS...] COMMAND\n\n"
|
|
|
|
"%sQuery and control the networking subsystem.%s\n"
|
2019-05-24 17:37:48 +02:00
|
|
|
"\nCommands:\n"
|
2019-10-23 15:36:04 +02:00
|
|
|
" list [PATTERN...] List links\n"
|
|
|
|
" status [PATTERN...] Show link status\n"
|
|
|
|
" lldp [PATTERN...] Show LLDP neighbors\n"
|
|
|
|
" label Show current address label entries in the kernel\n"
|
|
|
|
" delete DEVICES... Delete virtual netdevs\n"
|
2020-03-24 07:10:53 +01:00
|
|
|
" up DEVICES... Bring devices up\n"
|
|
|
|
" down DEVICES... Bring devices down\n"
|
2019-10-23 15:36:04 +02:00
|
|
|
" renew DEVICES... Renew dynamic configurations\n"
|
2020-02-19 07:42:26 +01:00
|
|
|
" forcerenew DEVICES... Trigger DHCP reconfiguration of all connected clients\n"
|
2019-10-23 15:36:04 +02:00
|
|
|
" reconfigure DEVICES... Reconfigure interfaces\n"
|
|
|
|
" reload Reload .network and .netdev files\n"
|
2019-11-15 18:38:44 +01:00
|
|
|
"\nOptions:\n"
|
2019-10-23 15:36:04 +02:00
|
|
|
" -h --help Show this help\n"
|
|
|
|
" --version Show package version\n"
|
|
|
|
" --no-pager Do not pipe output into a pager\n"
|
|
|
|
" --no-legend Do not show the headers and footers\n"
|
|
|
|
" -a --all Show status for all links\n"
|
|
|
|
" -s --stats Show detailed link statics\n"
|
2020-01-07 03:32:03 +01:00
|
|
|
" -l --full Do not ellipsize output\n"
|
|
|
|
" -n --lines=INTEGER Number of journal entries to show\n"
|
2018-08-09 10:32:31 +02:00
|
|
|
"\nSee the %s for details.\n"
|
|
|
|
, program_invocation_short_name
|
2019-11-15 18:38:44 +01:00
|
|
|
, ansi_highlight()
|
2019-10-08 18:19:59 +02:00
|
|
|
, ansi_normal()
|
2018-08-09 10:32:31 +02:00
|
|
|
, link
|
|
|
|
);
|
|
|
|
|
|
|
|
return 0;
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_argv(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
enum {
|
|
|
|
ARG_VERSION = 0x100,
|
|
|
|
ARG_NO_PAGER,
|
|
|
|
ARG_NO_LEGEND,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct option options[] = {
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "version", no_argument, NULL, ARG_VERSION },
|
|
|
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
|
|
|
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
|
2014-08-12 15:19:30 +02:00
|
|
|
{ "all", no_argument, NULL, 'a' },
|
2019-05-24 17:37:48 +02:00
|
|
|
{ "stats", no_argument, NULL, 's' },
|
2020-01-07 03:32:03 +01:00
|
|
|
{ "full", no_argument, NULL, 'l' },
|
|
|
|
{ "lines", required_argument, NULL, 'n' },
|
2014-08-12 01:41:42 +02:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
int c;
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
assert(argv);
|
|
|
|
|
2020-01-07 03:32:03 +01:00
|
|
|
while ((c = getopt_long(argc, argv, "hasln:", options, NULL)) >= 0) {
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
case 'h':
|
2018-08-09 10:32:31 +02:00
|
|
|
return help();
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
case ARG_VERSION:
|
2015-09-23 03:01:06 +02:00
|
|
|
return version();
|
2014-08-12 01:41:42 +02:00
|
|
|
|
|
|
|
case ARG_NO_PAGER:
|
2018-11-11 12:56:29 +01:00
|
|
|
arg_pager_flags |= PAGER_DISABLE;
|
2014-08-12 01:41:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ARG_NO_LEGEND:
|
|
|
|
arg_legend = false;
|
|
|
|
break;
|
|
|
|
|
2014-08-12 15:19:30 +02:00
|
|
|
case 'a':
|
|
|
|
arg_all = true;
|
|
|
|
break;
|
|
|
|
|
2019-05-24 17:37:48 +02:00
|
|
|
case 's':
|
|
|
|
arg_stats = true;
|
|
|
|
break;
|
|
|
|
|
2020-01-07 03:32:03 +01:00
|
|
|
case 'l':
|
|
|
|
arg_full = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'n':
|
|
|
|
if (safe_atou(optarg, &arg_lines) < 0)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Failed to parse lines '%s'", optarg);
|
|
|
|
break;
|
|
|
|
|
2014-08-12 01:41:42 +02:00
|
|
|
case '?':
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
default:
|
|
|
|
assert_not_reached("Unhandled option");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int networkctl_main(int argc, char *argv[]) {
|
2018-03-12 06:05:08 +01:00
|
|
|
static const Verb verbs[] = {
|
2019-10-23 15:36:04 +02:00
|
|
|
{ "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links },
|
|
|
|
{ "status", VERB_ANY, VERB_ANY, 0, link_status },
|
|
|
|
{ "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
|
|
|
|
{ "label", VERB_ANY, VERB_ANY, 0, list_address_labels },
|
|
|
|
{ "delete", 2, VERB_ANY, 0, link_delete },
|
2020-03-24 07:10:53 +01:00
|
|
|
{ "up", 2, VERB_ANY, 0, link_up_down },
|
|
|
|
{ "down", 2, VERB_ANY, 0, link_up_down },
|
2019-10-23 15:36:04 +02:00
|
|
|
{ "renew", 2, VERB_ANY, 0, link_renew },
|
2020-02-19 07:42:26 +01:00
|
|
|
{ "forcerenew", 2, VERB_ANY, 0, link_force_renew },
|
2019-10-23 15:36:04 +02:00
|
|
|
{ "reconfigure", 2, VERB_ANY, 0, verb_reconfigure },
|
|
|
|
{ "reload", 1, 1, 0, verb_reload },
|
2014-12-19 03:16:45 +01:00
|
|
|
{}
|
2014-08-12 01:41:42 +02:00
|
|
|
};
|
|
|
|
|
2014-12-19 03:16:45 +01:00
|
|
|
return dispatch_verb(argc, argv, verbs, NULL);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
|
|
|
|
2016-02-20 22:25:43 +01:00
|
|
|
static void warn_networkd_missing(void) {
|
|
|
|
|
|
|
|
if (access("/run/systemd/netif/state", F_OK) >= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
|
|
|
|
}
|
|
|
|
|
2018-11-20 09:57:30 +01:00
|
|
|
static int run(int argc, char* argv[]) {
|
2014-08-12 01:41:42 +02:00
|
|
|
int r;
|
|
|
|
|
2019-04-26 12:28:25 +02:00
|
|
|
log_show_color(true);
|
2014-08-12 01:41:42 +02:00
|
|
|
log_parse_environment();
|
|
|
|
log_open();
|
|
|
|
|
|
|
|
r = parse_argv(argc, argv);
|
|
|
|
if (r <= 0)
|
2018-11-20 09:57:30 +01:00
|
|
|
return r;
|
2014-08-12 01:41:42 +02:00
|
|
|
|
2016-02-20 22:25:43 +01:00
|
|
|
warn_networkd_missing();
|
|
|
|
|
2018-11-20 09:57:30 +01:00
|
|
|
return networkctl_main(argc, argv);
|
2014-08-12 01:41:42 +02:00
|
|
|
}
|
2018-11-20 09:57:30 +01:00
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION(run);
|