Merge pull request #31502 from yuwata/network-lldp-json
network: support to dump LLDP neighbors in JSON format
This commit is contained in:
+3
-3
@@ -302,15 +302,15 @@
|
||||
details.</para>
|
||||
|
||||
<para>Produces output similar to:
|
||||
<programlisting>LINK CHASSIS ID SYSTEM NAME CAPS PORT ID PORT DESCRIPTION
|
||||
enp0s25 00:e0:4c:00:00:00 GS1900 ..b........ 2 Port #2
|
||||
<programlisting>LINK SYSTEM-NAME SYSTEM-DESCRIPTION CHASSIS-ID PORT-ID PORT-DESCRIPTION CAPS
|
||||
enp0s25 GS1900 - 00:e0:4c:00:00:00 2 Port #2 ..b........
|
||||
|
||||
Capability Flags:
|
||||
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)
|
||||
|
||||
1 neighbors listed.</programlisting></para>
|
||||
1 neighbor(s) listed.</programlisting></para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v219"/>
|
||||
</listitem>
|
||||
|
||||
@@ -376,17 +376,6 @@ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_a
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(size, -EINVAL);
|
||||
|
||||
*ret = LLDP_NEIGHBOR_RAW(n);
|
||||
*size = n->raw_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
|
||||
assert_return(n, -EINVAL);
|
||||
assert_return(type, -EINVAL);
|
||||
@@ -640,28 +629,6 @@ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
|
||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
||||
int r;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(raw || raw_size <= 0, -EINVAL);
|
||||
|
||||
n = lldp_neighbor_new(raw_size);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_safe(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
|
||||
|
||||
r = lldp_neighbor_parse(n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(n);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
|
||||
assert_return(n, -EINVAL);
|
||||
|
||||
@@ -793,3 +760,31 @@ int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_
|
||||
*ret = triple_timestamp_by_clock(&n->timestamp, clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lldp_neighbor_build_json(sd_lldp_neighbor *n, JsonVariant **ret) {
|
||||
const char *chassis_id = NULL, *port_id = NULL, *port_description = NULL,
|
||||
*system_name = NULL, *system_description = NULL;
|
||||
uint16_t cc = 0;
|
||||
bool valid_cc;
|
||||
|
||||
assert(n);
|
||||
assert(ret);
|
||||
|
||||
(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_port_description(n, &port_description);
|
||||
(void) sd_lldp_neighbor_get_system_name(n, &system_name);
|
||||
(void) sd_lldp_neighbor_get_system_description(n, &system_description);
|
||||
|
||||
valid_cc = sd_lldp_neighbor_get_enabled_capabilities(n, &cc);
|
||||
|
||||
return json_build(ret, JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("ChassisID", chassis_id),
|
||||
JSON_BUILD_PAIR_BYTE_ARRAY("RawChassisID", n->id.chassis_id, n->id.chassis_id_size),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("PortID", port_id),
|
||||
JSON_BUILD_PAIR_BYTE_ARRAY("RawPortID", n->id.port_id, n->id.port_id_size),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("PortDescription", port_description),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("SystemName", system_name),
|
||||
JSON_BUILD_PAIR_STRING_NON_EMPTY("SystemDescription", system_description),
|
||||
JSON_BUILD_PAIR_CONDITION(valid_cc, "EnabledCapabilities", JSON_BUILD_UNSIGNED(cc))));
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "sd-lldp-rx.h"
|
||||
|
||||
#include "hash-funcs.h"
|
||||
#include "json.h"
|
||||
#include "lldp-rx-internal.h"
|
||||
#include "time-util.h"
|
||||
|
||||
@@ -90,3 +91,4 @@ sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size);
|
||||
int lldp_neighbor_parse(sd_lldp_neighbor *n);
|
||||
void lldp_neighbor_start_ttl(sd_lldp_neighbor *n);
|
||||
bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b);
|
||||
int lldp_neighbor_build_json(sd_lldp_neighbor *n, JsonVariant **ret);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "sd-lldp-rx.h"
|
||||
|
||||
#include "hashmap.h"
|
||||
#include "json.h"
|
||||
#include "network-common.h"
|
||||
#include "prioq.h"
|
||||
|
||||
@@ -36,6 +37,8 @@ struct sd_lldp_rx {
|
||||
const char* lldp_rx_event_to_string(sd_lldp_rx_event_t e) _const_;
|
||||
sd_lldp_rx_event_t lldp_rx_event_from_string(const char *s) _pure_;
|
||||
|
||||
int lldp_rx_build_neighbors_json(sd_lldp_rx *lldp_rx, JsonVariant **ret);
|
||||
|
||||
#define log_lldp_rx_errno(lldp_rx, error, fmt, ...) \
|
||||
log_interface_prefix_full_errno( \
|
||||
"LLDP Rx: ", \
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "ether-addr-util.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "json.h"
|
||||
#include "lldp-neighbor.h"
|
||||
#include "lldp-network.h"
|
||||
#include "lldp-rx-internal.h"
|
||||
@@ -490,6 +491,30 @@ int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***ret) {
|
||||
return k;
|
||||
}
|
||||
|
||||
int lldp_rx_build_neighbors_json(sd_lldp_rx *lldp_rx, JsonVariant **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
int r;
|
||||
|
||||
assert(lldp_rx);
|
||||
assert(ret);
|
||||
|
||||
sd_lldp_neighbor *n;
|
||||
HASHMAP_FOREACH(n, lldp_rx->neighbor_by_id) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
|
||||
|
||||
r = lldp_neighbor_build_json(n, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_variant_append_array(&v, w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_lldp_rx_set_neighbors_max(sd_lldp_rx *lldp_rx, uint64_t m) {
|
||||
assert_return(lldp_rx, -EINVAL);
|
||||
assert_return(m > 0, -EINVAL);
|
||||
|
||||
+204
-139
@@ -15,7 +15,6 @@
|
||||
#include "sd-device.h"
|
||||
#include "sd-dhcp-client.h"
|
||||
#include "sd-hwdb.h"
|
||||
#include "sd-lldp-rx.h"
|
||||
#include "sd-netlink.h"
|
||||
#include "sd-network.h"
|
||||
|
||||
@@ -93,11 +92,10 @@ JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_drop_in, freep);
|
||||
|
||||
static int check_netns_match(void) {
|
||||
struct stat st;
|
||||
uint64_t id;
|
||||
JsonVariant *reply = NULL;
|
||||
static int varlink_connect_networkd(Varlink **ret_varlink) {
|
||||
_cleanup_(varlink_unrefp) Varlink *vl = NULL;
|
||||
JsonVariant *reply;
|
||||
uint64_t id;
|
||||
int r;
|
||||
|
||||
r = varlink_connect_address(&vl, "/run/systemd/netif/io.systemd.Network");
|
||||
@@ -117,18 +115,21 @@ static int check_netns_match(void) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (id == 0) {
|
||||
if (id == 0)
|
||||
log_debug("systemd-networkd.service not running in a network namespace (?), skipping netns check.");
|
||||
return 0;
|
||||
else {
|
||||
struct stat st;
|
||||
|
||||
if (stat("/proc/self/ns/net", &st) < 0)
|
||||
return log_error_errno(errno, "Failed to determine our own network namespace ID: %m");
|
||||
|
||||
if (id != st.st_ino)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE),
|
||||
"networkctl must be invoked in same network namespace as systemd-networkd.service.");
|
||||
}
|
||||
|
||||
if (stat("/proc/self/ns/net", &st) < 0)
|
||||
return log_error_errno(errno, "Failed to determine our own network namespace ID: %m");
|
||||
|
||||
if (id != st.st_ino)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EREMOTE),
|
||||
"networkctl must be invoked in same network namespace as systemd-networkd.service.");
|
||||
|
||||
if (ret_varlink)
|
||||
*ret_varlink = TAKE_PTR(vl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -162,7 +163,7 @@ int acquire_bus(sd_bus **ret) {
|
||||
return log_error_errno(r, "Failed to connect to system bus: %m");
|
||||
|
||||
if (networkd_is_running()) {
|
||||
r = check_netns_match();
|
||||
r = varlink_connect_networkd(/* ret_varlink = */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
@@ -1311,96 +1312,96 @@ static int list_address_labels(int argc, char *argv[], void *userdata) {
|
||||
return dump_address_labels(rtnl);
|
||||
}
|
||||
|
||||
static int open_lldp_neighbors(int ifindex, FILE **ret) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char p[STRLEN("/run/systemd/netif/lldp/") + DECIMAL_STR_MAX(int)];
|
||||
typedef struct InterfaceInfo {
|
||||
int ifindex;
|
||||
const char *ifname;
|
||||
char **altnames;
|
||||
JsonVariant *v;
|
||||
} InterfaceInfo;
|
||||
|
||||
assert(ifindex >= 0);
|
||||
assert(ret);
|
||||
static void interface_info_done(InterfaceInfo *p) {
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
xsprintf(p, "/run/systemd/netif/lldp/%i", ifindex);
|
||||
|
||||
f = fopen(p, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
*ret = TAKE_PTR(f);
|
||||
return 0;
|
||||
strv_free(p->altnames);
|
||||
json_variant_unref(p->v);
|
||||
}
|
||||
|
||||
static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
|
||||
_cleanup_free_ void *raw = NULL;
|
||||
size_t l;
|
||||
le64_t u;
|
||||
int r;
|
||||
static const JsonDispatch interface_info_dispatch_table[] = {
|
||||
{ "InterfaceIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, offsetof(InterfaceInfo, ifindex), JSON_MANDATORY },
|
||||
{ "InterfaceName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(InterfaceInfo, ifname), JSON_MANDATORY },
|
||||
{ "InterfaceAlternativeNames", JSON_VARIANT_ARRAY, json_dispatch_strv, offsetof(InterfaceInfo, altnames), 0 },
|
||||
{ "Neighbors", JSON_VARIANT_ARRAY, json_dispatch_variant, offsetof(InterfaceInfo, v), 0 },
|
||||
{},
|
||||
};
|
||||
|
||||
assert(f);
|
||||
assert(ret);
|
||||
typedef struct LLDPNeighborInfo {
|
||||
const char *chassis_id;
|
||||
const char *port_id;
|
||||
const char *port_description;
|
||||
const char *system_name;
|
||||
const char *system_description;
|
||||
uint16_t capabilities;
|
||||
} LLDPNeighborInfo;
|
||||
|
||||
l = fread(&u, 1, sizeof(u), f);
|
||||
if (l == 0 && feof(f))
|
||||
return 0;
|
||||
if (l != sizeof(u))
|
||||
return -EBADMSG;
|
||||
static const JsonDispatch lldp_neighbor_dispatch_table[] = {
|
||||
{ "ChassisID", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LLDPNeighborInfo, chassis_id), 0 },
|
||||
{ "PortID", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LLDPNeighborInfo, port_id), 0 },
|
||||
{ "PortDescription", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LLDPNeighborInfo, port_description), 0 },
|
||||
{ "SystemName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LLDPNeighborInfo, system_name), 0 },
|
||||
{ "SystemDescription", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(LLDPNeighborInfo, system_description), 0 },
|
||||
{ "EnabledCapabilities", _JSON_VARIANT_TYPE_INVALID, json_dispatch_uint16, offsetof(LLDPNeighborInfo, capabilities), 0 },
|
||||
{},
|
||||
};
|
||||
|
||||
/* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
|
||||
if (le64toh(u) >= 4096)
|
||||
return -EBADMSG;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static int dump_lldp_neighbors(Table *table, const char *prefix, int ifindex) {
|
||||
static int dump_lldp_neighbors(Varlink *vl, Table *table, int ifindex) {
|
||||
_cleanup_strv_free_ char **buf = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
JsonVariant *reply;
|
||||
int r;
|
||||
|
||||
assert(vl);
|
||||
assert(table);
|
||||
assert(prefix);
|
||||
assert(ifindex > 0);
|
||||
|
||||
r = open_lldp_neighbors(ifindex, &f);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
r = varlink_callb_and_log(vl, "io.systemd.Network.GetLLDPNeighbors", &reply,
|
||||
JSON_BUILD_OBJECT(JSON_BUILD_PAIR_INTEGER("InterfaceIndex", ifindex)));
|
||||
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;
|
||||
JsonVariant *i;
|
||||
JSON_VARIANT_ARRAY_FOREACH(i, json_variant_by_key(reply, "Neighbors")) {
|
||||
_cleanup_(interface_info_done) InterfaceInfo info = {};
|
||||
|
||||
r = next_lldp_neighbor(f, &n);
|
||||
r = json_dispatch(i, interface_info_dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &info);
|
||||
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);
|
||||
if (info.ifindex != ifindex)
|
||||
continue;
|
||||
|
||||
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) ? "" : ")");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
JsonVariant *neighbor;
|
||||
JSON_VARIANT_ARRAY_FOREACH(neighbor, info.v) {
|
||||
LLDPNeighborInfo neighbor_info = {};
|
||||
|
||||
r = json_dispatch(neighbor, lldp_neighbor_dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &neighbor_info);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_extendf(&buf, "%s%s%s%s on port %s%s%s%s",
|
||||
strna(neighbor_info.system_name),
|
||||
isempty(neighbor_info.system_description) ? "" : " (",
|
||||
strempty(neighbor_info.system_description),
|
||||
isempty(neighbor_info.system_description) ? "" : ")",
|
||||
strna(neighbor_info.port_id),
|
||||
isempty(neighbor_info.port_description) ? "" : " (",
|
||||
strempty(neighbor_info.port_description),
|
||||
isempty(neighbor_info.port_description) ? "" : ")");
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
}
|
||||
}
|
||||
|
||||
return dump_list(table, prefix, buf);
|
||||
return dump_list(table, "Connected To", buf);
|
||||
}
|
||||
|
||||
static int dump_dhcp_leases(Table *table, const char *prefix, sd_bus *bus, const LinkInfo *link) {
|
||||
@@ -1683,6 +1684,7 @@ static int link_status_one(
|
||||
sd_bus *bus,
|
||||
sd_netlink *rtnl,
|
||||
sd_hwdb *hwdb,
|
||||
Varlink *vl,
|
||||
const LinkInfo *info) {
|
||||
|
||||
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL,
|
||||
@@ -1698,6 +1700,7 @@ static int link_status_one(
|
||||
|
||||
assert(bus);
|
||||
assert(rtnl);
|
||||
assert(vl);
|
||||
assert(info);
|
||||
|
||||
(void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
|
||||
@@ -2316,7 +2319,7 @@ static int link_status_one(
|
||||
return table_log_add_error(r);
|
||||
}
|
||||
|
||||
r = dump_lldp_neighbors(table, "Connected To", info->ifindex);
|
||||
r = dump_lldp_neighbors(vl, table, info->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -2424,6 +2427,7 @@ static int link_status(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
_cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
|
||||
_cleanup_(varlink_unrefp) Varlink *vl = NULL;
|
||||
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
|
||||
int r, c;
|
||||
|
||||
@@ -2448,6 +2452,10 @@ static int link_status(int argc, char *argv[], void *userdata) {
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to open hardware database: %m");
|
||||
|
||||
r = varlink_connect_networkd(&vl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_all)
|
||||
c = acquire_link_info(bus, rtnl, NULL, &links);
|
||||
else if (argc <= 1)
|
||||
@@ -2464,7 +2472,7 @@ static int link_status(int argc, char *argv[], void *userdata) {
|
||||
if (!first)
|
||||
putchar('\n');
|
||||
|
||||
RET_GATHER(r, link_status_one(bus, rtnl, hwdb, i));
|
||||
RET_GATHER(r, link_status_one(bus, rtnl, hwdb, vl, i));
|
||||
|
||||
first = false;
|
||||
}
|
||||
@@ -2472,7 +2480,7 @@ static int link_status(int argc, char *argv[], void *userdata) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static char *lldp_capabilities_to_string(uint16_t x) {
|
||||
static char *lldp_capabilities_to_string(uint64_t x) {
|
||||
static const char characters[] = {
|
||||
'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
|
||||
};
|
||||
@@ -2522,30 +2530,94 @@ static void lldp_capabilities_legend(uint16_t x) {
|
||||
puts("");
|
||||
}
|
||||
|
||||
static int link_lldp_status(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||
_cleanup_(link_info_array_freep) LinkInfo *links = NULL;
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
int r, c, m = 0;
|
||||
uint16_t all = 0;
|
||||
TableCell *cell;
|
||||
static bool interface_match_pattern(const InterfaceInfo *info, char * const *patterns) {
|
||||
assert(info);
|
||||
|
||||
r = sd_netlink_open(&rtnl);
|
||||
if (strv_isempty(patterns))
|
||||
return true;
|
||||
|
||||
if (strv_fnmatch(patterns, info->ifname))
|
||||
return true;
|
||||
|
||||
char str[DECIMAL_STR_MAX(int)];
|
||||
xsprintf(str, "%i", info->ifindex);
|
||||
if (strv_fnmatch(patterns, str))
|
||||
return true;
|
||||
|
||||
STRV_FOREACH(a, info->altnames)
|
||||
if (strv_fnmatch(patterns, *a))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int dump_lldp_neighbors_json(JsonVariant *reply, char * const *patterns) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL, *v = NULL;
|
||||
int r;
|
||||
|
||||
assert(reply);
|
||||
|
||||
if (strv_isempty(patterns))
|
||||
return json_variant_dump(reply, arg_json_format_flags, NULL, NULL);
|
||||
|
||||
/* Filter and dump the result. */
|
||||
|
||||
JsonVariant *i;
|
||||
JSON_VARIANT_ARRAY_FOREACH(i, json_variant_by_key(reply, "Neighbors")) {
|
||||
_cleanup_(interface_info_done) InterfaceInfo info = {};
|
||||
|
||||
r = json_dispatch(i, interface_info_dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &info);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!interface_match_pattern(&info, patterns))
|
||||
continue;
|
||||
|
||||
r = json_variant_append_array(&array, i);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to append json variant to array: %m");
|
||||
}
|
||||
|
||||
r = json_build(&v,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_CONDITION(json_variant_is_blank_array(array), "Neighbors", JSON_BUILD_EMPTY_ARRAY),
|
||||
JSON_BUILD_PAIR_CONDITION(!json_variant_is_blank_array(array), "Neighbors", JSON_BUILD_VARIANT(array))));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to connect to netlink: %m");
|
||||
return log_error_errno(r, "Failed to build json varinat: %m");
|
||||
|
||||
c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
|
||||
if (c < 0)
|
||||
return c;
|
||||
return json_variant_dump(v, arg_json_format_flags, NULL, NULL);
|
||||
}
|
||||
|
||||
static int link_lldp_status(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(varlink_unrefp) Varlink *vl = NULL;
|
||||
_cleanup_(table_unrefp) Table *table = NULL;
|
||||
JsonVariant *reply;
|
||||
uint64_t all = 0;
|
||||
TableCell *cell;
|
||||
size_t m = 0;
|
||||
int r;
|
||||
|
||||
r = varlink_connect_networkd(&vl);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = varlink_call_and_log(vl, "io.systemd.Network.GetLLDPNeighbors", NULL, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (arg_json_format_flags != JSON_FORMAT_OFF)
|
||||
return dump_lldp_neighbors_json(reply, strv_skip(argv, 1));
|
||||
|
||||
pager_open(arg_pager_flags);
|
||||
|
||||
table = table_new("link",
|
||||
"chassis-id",
|
||||
table = table_new("index",
|
||||
"link",
|
||||
"system-name",
|
||||
"caps",
|
||||
"system-description",
|
||||
"chassis-id",
|
||||
"port-id",
|
||||
"port-description");
|
||||
"port-description",
|
||||
"caps");
|
||||
if (!table)
|
||||
return log_oom();
|
||||
|
||||
@@ -2553,53 +2625,46 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
|
||||
table_set_width(table, 0);
|
||||
|
||||
table_set_header(table, arg_legend);
|
||||
|
||||
assert_se(cell = table_get_cell(table, 0, 3));
|
||||
table_set_minimum_width(table, cell, 11);
|
||||
table_set_ersatz_string(table, TABLE_ERSATZ_DASH);
|
||||
table_set_sort(table, (size_t) 0, (size_t) 2);
|
||||
table_hide_column_from_display(table, (size_t) 0);
|
||||
|
||||
FOREACH_ARRAY(link, links, c) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
/* Make the capabilities not truncated */
|
||||
assert_se(cell = table_get_cell(table, 0, 7));
|
||||
table_set_minimum_width(table, cell, 11);
|
||||
|
||||
r = open_lldp_neighbors(link->ifindex, &f);
|
||||
if (r == -ENOENT)
|
||||
JsonVariant *i;
|
||||
JSON_VARIANT_ARRAY_FOREACH(i, json_variant_by_key(reply, "Neighbors")) {
|
||||
_cleanup_(interface_info_done) InterfaceInfo info = {};
|
||||
|
||||
r = json_dispatch(i, interface_info_dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &info);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!interface_match_pattern(&info, strv_skip(argv, 1)))
|
||||
continue;
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", link->ifindex);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL;
|
||||
_cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
|
||||
_cleanup_free_ char *capabilities = NULL;
|
||||
uint16_t cc;
|
||||
JsonVariant *neighbor;
|
||||
JSON_VARIANT_ARRAY_FOREACH(neighbor, info.v) {
|
||||
LLDPNeighborInfo neighbor_info = {};
|
||||
|
||||
r = next_lldp_neighbor(f, &n);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to read neighbor data: %m");
|
||||
break;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
r = json_dispatch(neighbor, lldp_neighbor_dispatch_table, JSON_LOG|JSON_ALLOW_EXTENSIONS, &neighbor_info);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
(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);
|
||||
all |= neighbor_info.capabilities;
|
||||
|
||||
if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
|
||||
capabilities = lldp_capabilities_to_string(cc);
|
||||
all |= cc;
|
||||
}
|
||||
_cleanup_free_ char *cap_str = lldp_capabilities_to_string(neighbor_info.capabilities);
|
||||
|
||||
r = table_add_many(table,
|
||||
TABLE_STRING, link->name,
|
||||
TABLE_STRING, chassis_id,
|
||||
TABLE_STRING, system_name,
|
||||
TABLE_STRING, capabilities,
|
||||
TABLE_STRING, port_id,
|
||||
TABLE_STRING, port_description);
|
||||
TABLE_INT, info.ifindex,
|
||||
TABLE_STRING, info.ifname,
|
||||
TABLE_STRING, neighbor_info.system_name,
|
||||
TABLE_STRING, neighbor_info.system_description,
|
||||
TABLE_STRING, neighbor_info.chassis_id,
|
||||
TABLE_STRING, neighbor_info.port_id,
|
||||
TABLE_STRING, neighbor_info.port_description,
|
||||
TABLE_STRING, cap_str);
|
||||
if (r < 0)
|
||||
return table_log_add_error(r);
|
||||
|
||||
@@ -2613,7 +2678,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
|
||||
|
||||
if (arg_legend) {
|
||||
lldp_capabilities_legend(all);
|
||||
printf("\n%i neighbors listed.\n", m);
|
||||
printf("\n%zu neighbor(s) listed.\n", m);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -272,7 +272,6 @@ static Link *link_free(Link *link) {
|
||||
free(link->driver);
|
||||
|
||||
unlink_and_free(link->lease_file);
|
||||
unlink_and_free(link->lldp_file);
|
||||
unlink_and_free(link->state_file);
|
||||
|
||||
sd_device_unref(link->dev);
|
||||
@@ -2653,7 +2652,7 @@ static Link *link_drop_or_unref(Link *link) {
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_drop_or_unref);
|
||||
|
||||
static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||
_cleanup_free_ char *ifname = NULL, *kind = NULL, *state_file = NULL, *lease_file = NULL, *lldp_file = NULL;
|
||||
_cleanup_free_ char *ifname = NULL, *kind = NULL, *state_file = NULL, *lease_file = NULL;
|
||||
_cleanup_(link_drop_or_unrefp) Link *link = NULL;
|
||||
unsigned short iftype;
|
||||
int r, ifindex;
|
||||
@@ -2694,9 +2693,6 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||
|
||||
if (asprintf(&lease_file, "/run/systemd/netif/leases/%d", ifindex) < 0)
|
||||
return log_oom_debug();
|
||||
|
||||
if (asprintf(&lldp_file, "/run/systemd/netif/lldp/%d", ifindex) < 0)
|
||||
return log_oom_debug();
|
||||
}
|
||||
|
||||
link = new(Link, 1);
|
||||
@@ -2719,7 +2715,6 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
||||
|
||||
.state_file = TAKE_PTR(state_file),
|
||||
.lease_file = TAKE_PTR(lease_file),
|
||||
.lldp_file = TAKE_PTR(lldp_file),
|
||||
|
||||
.n_dns = UINT_MAX,
|
||||
.dns_default_route = -1,
|
||||
|
||||
@@ -181,7 +181,6 @@ typedef struct Link {
|
||||
|
||||
/* This is about LLDP reception */
|
||||
sd_lldp_rx *lldp_rx;
|
||||
char *lldp_file;
|
||||
|
||||
/* This is about LLDP transmission */
|
||||
sd_lldp_tx *lldp_tx;
|
||||
|
||||
@@ -52,8 +52,6 @@ static void lldp_rx_handler(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_ll
|
||||
Link *link = ASSERT_PTR(userdata);
|
||||
int r;
|
||||
|
||||
(void) link_lldp_save(link);
|
||||
|
||||
if (link->lldp_tx && event == SD_LLDP_RX_EVENT_ADDED) {
|
||||
/* If we received information about a new neighbor, restart the LLDP "fast" logic */
|
||||
|
||||
@@ -104,70 +102,3 @@ int link_lldp_rx_configure(Link *link) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_lldp_save(Link *link) {
|
||||
_cleanup_(unlink_and_freep) char *temp_path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
sd_lldp_neighbor **l = NULL;
|
||||
int n = 0, r, i;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (isempty(link->lldp_file))
|
||||
return 0; /* Do not update state file when running in test mode. */
|
||||
|
||||
if (!link->lldp_rx) {
|
||||
(void) unlink(link->lldp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_lldp_rx_get_neighbors(link->lldp_rx, &l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
(void) unlink(link->lldp_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
n = r;
|
||||
|
||||
r = fopen_temporary(link->lldp_file, &f, &temp_path);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
(void) fchmod(fileno(f), 0644);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
const void *p;
|
||||
le64_t u;
|
||||
size_t sz;
|
||||
|
||||
r = sd_lldp_neighbor_get_raw(l[i], &p, &sz);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
u = htole64(sz);
|
||||
fwrite(&u, 1, sizeof(u), f);
|
||||
fwrite(p, 1, sz, f);
|
||||
}
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = conservative_rename(temp_path, link->lldp_file);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
finish:
|
||||
if (r < 0)
|
||||
log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
|
||||
|
||||
if (l) {
|
||||
for (i = 0; i < n; i++)
|
||||
sd_lldp_neighbor_unref(l[i]);
|
||||
free(l);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ typedef enum LLDPMode {
|
||||
} LLDPMode;
|
||||
|
||||
int link_lldp_rx_configure(Link *link);
|
||||
int link_lldp_save(Link *link);
|
||||
|
||||
const char* lldp_mode_to_string(LLDPMode m) _const_;
|
||||
LLDPMode lldp_mode_from_string(const char *s) _pure_;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lldp-rx-internal.h"
|
||||
#include "networkd-manager-varlink.h"
|
||||
#include "varlink.h"
|
||||
#include "varlink-io.systemd.Network.h"
|
||||
@@ -56,6 +57,113 @@ static int vl_method_get_namespace_id(Varlink *link, JsonVariant *parameters, Va
|
||||
JSON_BUILD_PAIR_CONDITION(nsid != UINT32_MAX, "NamespaceNSID", JSON_BUILD_UNSIGNED(nsid))));
|
||||
}
|
||||
|
||||
typedef struct InterfaceInfo {
|
||||
int ifindex;
|
||||
const char *ifname;
|
||||
} InterfaceInfo;
|
||||
|
||||
static int dispatch_interface(Varlink *vlink, JsonVariant *parameters, Manager *manager, Link **ret) {
|
||||
static const JsonDispatch dispatch_table[] = {
|
||||
{ "InterfaceIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, offsetof(InterfaceInfo, ifindex), 0 },
|
||||
{ "InterfaceName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(InterfaceInfo, ifname), 0 },
|
||||
{}
|
||||
};
|
||||
|
||||
InterfaceInfo info = {};
|
||||
Link *link = NULL;
|
||||
int r;
|
||||
|
||||
assert(vlink);
|
||||
assert(manager);
|
||||
|
||||
r = varlink_dispatch(vlink, parameters, dispatch_table, &info);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (info.ifindex < 0)
|
||||
return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
|
||||
if (info.ifindex > 0 && link_get_by_index(manager, info.ifindex, &link) < 0)
|
||||
return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex"));
|
||||
if (info.ifname) {
|
||||
Link *link_by_name;
|
||||
|
||||
if (link_get_by_name(manager, info.ifname, &link_by_name) < 0)
|
||||
return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName"));
|
||||
|
||||
if (link && link_by_name != link)
|
||||
/* If both arguments are specified, then these must be consistent. */
|
||||
return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName"));
|
||||
|
||||
link = link_by_name;
|
||||
}
|
||||
|
||||
/* If neither InterfaceIndex nor InterfaceName specified, this function returns NULL. */
|
||||
*ret = link;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_append_lldp_neighbors(Link *link, JsonVariant *v, JsonVariant **array) {
|
||||
assert(link);
|
||||
assert(array);
|
||||
|
||||
return json_variant_append_arrayb(array,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_INTEGER("InterfaceIndex", link->ifindex),
|
||||
JSON_BUILD_PAIR_STRING("InterfaceName", link->ifname),
|
||||
JSON_BUILD_PAIR_STRV_NON_EMPTY("InterfaceAlternativeNames", link->alternative_names),
|
||||
JSON_BUILD_PAIR_CONDITION(json_variant_is_blank_array(v), "Neighbors", JSON_BUILD_EMPTY_ARRAY),
|
||||
JSON_BUILD_PAIR_CONDITION(!json_variant_is_blank_array(v), "Neighbors", JSON_BUILD_VARIANT(v))));
|
||||
}
|
||||
|
||||
static int vl_method_get_lldp_neighbors(Varlink *vlink, JsonVariant *parameters, VarlinkMethodFlags flags, Manager *manager) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *array = NULL;
|
||||
Link *link = NULL;
|
||||
int r;
|
||||
|
||||
assert(vlink);
|
||||
assert(manager);
|
||||
|
||||
r = dispatch_interface(vlink, parameters, manager, &link);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (link) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
|
||||
if (link->lldp_rx) {
|
||||
r = lldp_rx_build_neighbors_json(link->lldp_rx, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = link_append_lldp_neighbors(link, v, &array);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
HASHMAP_FOREACH(link, manager->links_by_index) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
|
||||
|
||||
if (!link->lldp_rx)
|
||||
continue;
|
||||
|
||||
r = lldp_rx_build_neighbors_json(link->lldp_rx, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (json_variant_is_blank_array(v))
|
||||
continue;
|
||||
|
||||
r = link_append_lldp_neighbors(link, v, &array);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return varlink_replyb(vlink,
|
||||
JSON_BUILD_OBJECT(
|
||||
JSON_BUILD_PAIR_CONDITION(json_variant_is_blank_array(array), "Neighbors", JSON_BUILD_EMPTY_ARRAY),
|
||||
JSON_BUILD_PAIR_CONDITION(!json_variant_is_blank_array(array), "Neighbors", JSON_BUILD_VARIANT(array))));
|
||||
}
|
||||
|
||||
int manager_connect_varlink(Manager *m) {
|
||||
_cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL;
|
||||
int r;
|
||||
@@ -78,7 +186,8 @@ int manager_connect_varlink(Manager *m) {
|
||||
r = varlink_server_bind_method_many(
|
||||
s,
|
||||
"io.systemd.Network.GetStates", vl_method_get_states,
|
||||
"io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id);
|
||||
"io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id,
|
||||
"io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to register varlink methods: %m");
|
||||
|
||||
|
||||
@@ -583,8 +583,6 @@ static int link_save(Link *link) {
|
||||
if (link->state == LINK_STATE_LINGER)
|
||||
return 0;
|
||||
|
||||
link_lldp_save(link);
|
||||
|
||||
admin_state = link_state_to_string(link->state);
|
||||
assert(admin_state);
|
||||
|
||||
|
||||
@@ -72,8 +72,7 @@ static int run(int argc, char *argv[]) {
|
||||
* to support old kernels not supporting AmbientCapabilities=. */
|
||||
FOREACH_STRING(p,
|
||||
"/run/systemd/netif/links/",
|
||||
"/run/systemd/netif/leases/",
|
||||
"/run/systemd/netif/lldp/") {
|
||||
"/run/systemd/netif/leases/") {
|
||||
r = mkdir_safe_label(p, 0755, UID_INVALID, GID_INVALID, MKDIR_WARN_MODE);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Could not create directory '%s': %m", p);
|
||||
|
||||
@@ -16,8 +16,35 @@ static VARLINK_DEFINE_METHOD(
|
||||
VARLINK_DEFINE_OUTPUT(NamespaceId, VARLINK_INT, 0),
|
||||
VARLINK_DEFINE_OUTPUT(NamespaceNSID, VARLINK_INT, VARLINK_NULLABLE));
|
||||
|
||||
static VARLINK_DEFINE_STRUCT_TYPE(
|
||||
LLDPNeighbor,
|
||||
VARLINK_DEFINE_FIELD(ChassisID, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(RawChassisID, VARLINK_INT, VARLINK_ARRAY),
|
||||
VARLINK_DEFINE_FIELD(PortID, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(RawPortID, VARLINK_INT, VARLINK_ARRAY),
|
||||
VARLINK_DEFINE_FIELD(PortDescription, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(SystemName, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(SystemDescription, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD(EnabledCapabilities, VARLINK_INT, VARLINK_NULLABLE));
|
||||
|
||||
static VARLINK_DEFINE_STRUCT_TYPE(
|
||||
LLDPNeighborsByInterface,
|
||||
VARLINK_DEFINE_FIELD(InterfaceIndex, VARLINK_INT, 0),
|
||||
VARLINK_DEFINE_FIELD(InterfaceName, VARLINK_STRING, 0),
|
||||
VARLINK_DEFINE_FIELD(InterfaceAlternativeNames, VARLINK_STRING, VARLINK_ARRAY|VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_FIELD_BY_TYPE(Neighbors, LLDPNeighbor, VARLINK_ARRAY));
|
||||
|
||||
static VARLINK_DEFINE_METHOD(
|
||||
GetLLDPNeighbors,
|
||||
VARLINK_DEFINE_INPUT(InterfaceIndex, VARLINK_INT, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_INPUT(InterfaceName, VARLINK_STRING, VARLINK_NULLABLE),
|
||||
VARLINK_DEFINE_OUTPUT_BY_TYPE(Neighbors, LLDPNeighborsByInterface, VARLINK_ARRAY));
|
||||
|
||||
VARLINK_DEFINE_INTERFACE(
|
||||
io_systemd_Network,
|
||||
"io.systemd.Network",
|
||||
&vl_method_GetStates,
|
||||
&vl_method_GetNamespaceId);
|
||||
&vl_method_GetNamespaceId,
|
||||
&vl_method_GetLLDPNeighbors,
|
||||
&vl_type_LLDPNeighbor,
|
||||
&vl_type_LLDPNeighborsByInterface);
|
||||
|
||||
@@ -68,7 +68,6 @@ int sd_lldp_rx_set_filter_address(sd_lldp_rx *lldp_rx, const struct ether_addr *
|
||||
|
||||
int sd_lldp_rx_get_neighbors(sd_lldp_rx *lldp_rx, sd_lldp_neighbor ***neighbors);
|
||||
|
||||
int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size);
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n);
|
||||
sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n);
|
||||
|
||||
@@ -76,7 +75,6 @@ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n);
|
||||
int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address);
|
||||
int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address);
|
||||
int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret);
|
||||
int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
|
||||
|
||||
/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */
|
||||
int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
|
||||
|
||||
@@ -5332,6 +5332,39 @@ class NetworkdLLDPTests(unittest.TestCase, Utilities):
|
||||
else:
|
||||
self.fail()
|
||||
|
||||
# With interface name
|
||||
output = networkctl('lldp', 'veth99');
|
||||
print(output)
|
||||
self.assertRegex(output, r'veth99 .* veth-peer')
|
||||
|
||||
# With interface name pattern
|
||||
output = networkctl('lldp', 've*9');
|
||||
print(output)
|
||||
self.assertRegex(output, r'veth99 .* veth-peer')
|
||||
|
||||
# json format
|
||||
output = networkctl('--json=short', 'lldp')
|
||||
print(output)
|
||||
self.assertIn('"InterfaceName":"veth99"', output)
|
||||
self.assertIn('"PortID":"veth-peer"', output)
|
||||
|
||||
# json format with interface name
|
||||
output = networkctl('--json=short', 'lldp', 'veth99')
|
||||
print(output)
|
||||
self.assertIn('"InterfaceName":"veth99"', output)
|
||||
self.assertIn('"PortID":"veth-peer"', output)
|
||||
|
||||
# json format with interface name pattern
|
||||
output = networkctl('--json=short', 'lldp', 've*9')
|
||||
print(output)
|
||||
self.assertIn('"InterfaceName":"veth99"', output)
|
||||
self.assertIn('"PortID":"veth-peer"', output)
|
||||
|
||||
# LLDP neighbors in status
|
||||
output = networkctl_status('veth99')
|
||||
print(output)
|
||||
self.assertRegex(output, r'Connected To: .* on port veth-peer')
|
||||
|
||||
class NetworkdRATests(unittest.TestCase, Utilities):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -10,4 +10,3 @@
|
||||
d /run/systemd/netif 0755 systemd-network systemd-network -
|
||||
d /run/systemd/netif/links 0755 systemd-network systemd-network -
|
||||
d /run/systemd/netif/leases 0755 systemd-network systemd-network -
|
||||
d /run/systemd/netif/lldp 0755 systemd-network systemd-network -
|
||||
|
||||
Reference in New Issue
Block a user