Merge pull request #2685 from poettering/lldp-fixes2

lldp fixes, second iteration
This commit is contained in:
Tom Gundersen
2016-02-22 17:38:34 +01:00
96 changed files with 2849 additions and 3087 deletions

View File

@@ -3299,14 +3299,10 @@ libsystemd_network_la_SOURCES = \
src/libsystemd-network/dhcp-identifier.h \
src/libsystemd-network/dhcp-identifier.c \
src/libsystemd-network/lldp.h \
src/libsystemd-network/lldp-tlv.h \
src/libsystemd-network/lldp-tlv.c \
src/libsystemd-network/lldp-network.h \
src/libsystemd-network/lldp-network.c \
src/libsystemd-network/lldp-port.h \
src/libsystemd-network/lldp-port.c \
src/libsystemd-network/lldp-internal.h \
src/libsystemd-network/lldp-internal.c \
src/libsystemd-network/lldp-neighbor.h \
src/libsystemd-network/lldp-neighbor.c \
src/libsystemd-network/sd-lldp.c
libsystemd_network_la_LIBADD = \
@@ -3389,9 +3385,6 @@ test_dhcp6_client_LDADD = \
libshared.la
test_lldp_SOURCES = \
src/libsystemd-network/lldp.h \
src/libsystemd-network/lldp-tlv.h \
src/libsystemd-network/lldp-tlv.c \
src/libsystemd-network/test-lldp.c
test_lldp_LDADD = \
@@ -5348,7 +5341,9 @@ libnetworkd_core_la_SOURCES = \
src/network/networkd-address-pool.h \
src/network/networkd-address-pool.c \
src/network/networkd-util.h \
src/network/networkd-util.c
src/network/networkd-util.c \
src/network/networkd-lldp-tx.h \
src/network/networkd-lldp-tx.c
nodist_libnetworkd_core_la_SOURCES = \
src/network/networkd-network-gperf.c \

9
TODO
View File

@@ -33,6 +33,14 @@ Janitorial Clean-ups:
Features:
* when using UTF8, ellipsize with "…" rather than "...", so that we can show more contents before truncating
* machinectl remove --hidden + machinectl remove --all
* move specifier expansion from service_spawn() into load-fragment.c
* optionally, also require WATCHDOG=1 notifications during service start-up and shutdown
* resolved: maybe, after all, implement local listening for DNS packets on port
53.
@@ -773,7 +781,6 @@ Features:
- work with non-Ethernet devices
- add support for more bond options
- dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from?
- add LLDP client side support
- the DHCP lease data (such as NTP/DNS) is still made available when
a carrier is lost on a link. It should be removed instantly.
- expose in the API the following bits:

View File

@@ -933,12 +933,12 @@
<title>Download a Fedora image, set a root password in it, start
it as service</title>
<programlisting># machinectl pull-raw --verify=no http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/21/Cloud/Images/x86_64/Fedora-Cloud-Base-20141203-21.x86_64.raw.xz
# systemd-nspawn -M Fedora-Cloud-Base-20141203-21
<programlisting># machinectl pull-raw --verify=no http://ftp.halifax.rwth-aachen.de/fedora/linux/releases/23/Cloud/x86_64/Images/Fedora-Cloud-Base-23-20151030.x86_64.raw.xz
# systemd-nspawn -M Fedora-Cloud-Base-23-20151030
# passwd
# exit
# machinectl start Fedora-Cloud-Base-20141203-21
# machinectl login Fedora-Cloud-Base-20141203-21</programlisting>
# machinectl start Fedora-Cloud-Base-23-20151030
# machinectl login Fedora-Cloud-Base-23-20151030</programlisting>
<para>This downloads the specified <filename>.raw</filename>
image with verification disabled. Then, a shell is opened in it

View File

@@ -102,12 +102,14 @@
<varlistentry>
<term>
<command>list</command>
<optional><replaceable>LINK...</replaceable></optional>
</term>
<listitem>
<para>Show a list of existing links and their
status. Produces output similar to <programlisting>
IDX LINK TYPE OPERATIONAL SETUP
<para>Show a list of existing links and their status. If no further arguments are specified shows all links,
otherwise just the specified links. Produces output similar to:
<programlisting>IDX LINK TYPE OPERATIONAL SETUP
1 lo loopback carrier unmanaged
2 eth0 ether routable configured
3 virbr0 ether no-carrier unmanaged
@@ -128,10 +130,10 @@ IDX LINK TYPE OPERATIONAL SETUP
state, kernel module driver, hardware and IP address,
configured DNS servers, etc.</para>
<para>When no links are specified, routable links are
shown. Also see the option <option>--all</option>.</para>
<para>When no links are specified, an overall network status is shown. Also see the option
<option>--all</option>.</para>
<para>Produces output similar to
<para>Produces output similar to:
<programlisting>
● State: routable
Address: 10.193.76.5 on eth0
@@ -148,11 +150,26 @@ IDX LINK TYPE OPERATIONAL SETUP
<varlistentry>
<term>
<command>lldp</command>
<optional><replaceable>LINK...</replaceable></optional>
</term>
<listitem>
<para>Show LLDP (Link Layer Discovery Protocol)
status.</para>
<para>Show discovered LLDP (Link Layer Discovery Protocol) neighbors. If one or more link names are specified
only neighbors on those interfaces are shown. Otherwise shows discovered neighbors on all interfaces. Note
that for this feature to work, <varname>LLDP=</varname> must be turned on on the specific interface, see
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
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
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>
</listitem>
</varlistentry>
</variablelist>

View File

@@ -335,10 +335,36 @@
<varlistentry>
<term><varname>LLDP=</varname></term>
<listitem>
<para>A boolean. When true, enables LLDP link receive support.
<para>Controls support for Ethernet LLDP packet reception. LLDP is a link-layer protocol commonly
implemented on professional routers and bridges which announces which physical port a system is connected
to, as well as other related data. Accepts a boolean or the special value
<literal>routers-only</literal>. When true, incoming LLDP packets are accepted and a database of all LLDP
neighbors maintained. If <literal>routers-only</literal> is set only LLDP data of various types of routers
is collected and LLDP data about other types of devices ignored (such as stations, telephones and
others). If false, LLDP reception is disabled. Defaults to <literal>routers-only</literal>. Use
<citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> to query the
collected neighbor data. LLDP is only available on Ethernet links. See <varname>EmitLLDP=</varname> below
for enabling LLDP packet emission from the local system.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>EmitLLDP=</varname></term>
<listitem>
<para>Controls support for Ethernet LLDP packet emission. Accepts a boolean parameter and defaults to
false. If enabled a short LLDP packet with information about the local system is sent out in regular
intervals on the link. The LLDP packet will contain information about the local host name, the local
machine ID (as stored in
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>) and the
local interface name, as well as the pretty hostname of the system (as set in
<citerefentry><refentrytitle>machine-info</refentrytitle><manvolnum>5</manvolnum></citerefentry>). LLDP
emission is only available on Ethernet links. Note that this setting passed data suitable for
identification of host to the network and should thus not be used on untrusted networks, where such
identification data should not be made available. Use this option to enable other systems to identify on
which interface they are connected to this system. See <varname>LLDP=</varname> above for an option to
enable LLDP reception.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>BindCarrier=</varname></term>
<listitem>

View File

@@ -12,6 +12,8 @@ Name=host0
[Network]
DHCP=yes
LinkLocalAddressing=yes
LLDP=yes
EmitLLDP=yes
[DHCP]
UseTimezone=yes

View File

@@ -15,3 +15,5 @@ Address=0.0.0.0/28
LinkLocalAddressing=yes
DHCPServer=yes
IPMasquerade=yes
LLDP=yes
EmitLLDP=yes

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <stdbool.h>
#include "path-lookup.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>

View File

@@ -42,3 +42,26 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR
return buffer;
}
bool ether_addr_is_null(const struct ether_addr *addr) {
assert(addr);
return addr->ether_addr_octet[0] == 0 &&
addr->ether_addr_octet[1] == 0 &&
addr->ether_addr_octet[2] == 0 &&
addr->ether_addr_octet[3] == 0 &&
addr->ether_addr_octet[4] == 0 &&
addr->ether_addr_octet[5] == 0;
}
bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
assert(a);
assert(b);
return a->ether_addr_octet[0] == b->ether_addr_octet[0] &&
a->ether_addr_octet[1] == b->ether_addr_octet[1] &&
a->ether_addr_octet[2] == b->ether_addr_octet[2] &&
a->ether_addr_octet[3] == b->ether_addr_octet[3] &&
a->ether_addr_octet[4] == b->ether_addr_octet[4] &&
a->ether_addr_octet[5] == b->ether_addr_octet[5];
}

View File

@@ -20,10 +20,13 @@
***/
#include <net/ethernet.h>
#include <stdbool.h>
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
#define ETHER_ADDR_TO_STRING_MAX (3*6)
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]);
bool ether_addr_is_null(const struct ether_addr *addr);
bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b);

View File

@@ -1,11 +1,11 @@
#pragma once
/* gunicode.h - Unicode manipulation functions
*
* Copyright (C) 1999, 2000 Tom Tromey
* Copyright 2000, 2005 Red Hat, Inc.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

View File

@@ -48,6 +48,9 @@ bool hostname_is_set(void) {
char* gethostname_malloc(void) {
struct utsname u;
/* This call tries to return something useful, either the actual hostname or it makes something up. The only
* reason it might mail is OOM. It might even return "localhost" if that's set. */
assert_se(uname(&u) >= 0);
if (isempty(u.nodename) || streq(u.nodename, "(none)"))
@@ -56,6 +59,31 @@ char* gethostname_malloc(void) {
return strdup(u.nodename);
}
int gethostname_strict(char **ret) {
struct utsname u;
char *k;
/* This call will rather fail than make up a name. It will not return "localhost" either. */
assert_se(uname(&u) >= 0);
if (isempty(u.nodename))
return -ENXIO;
if (streq(u.nodename, "(none)"))
return -ENXIO;
if (is_localhost(u.nodename))
return -ENXIO;
k = strdup(u.nodename);
if (!k)
return -ENOMEM;
*ret = k;
return 0;
}
static bool hostname_valid_char(char c) {
return
(c >= 'a' && c <= 'z') ||

View File

@@ -26,6 +26,7 @@
bool hostname_is_set(void);
char* gethostname_malloc(void);
int gethostname_strict(char **ret);
bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
char* hostname_cleanup(char *s);

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <stdbool.h>
#include <unistd.h>

View File

@@ -31,6 +31,7 @@
#include <linux/neighbour.h>
#include <linux/oom.h>
#include <linux/rtnetlink.h>
#include <net/ethernet.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/syscall.h>
@@ -1171,4 +1172,8 @@ static inline key_serial_t request_key(const char *type, const char *description
#define char16_t uint16_t
#endif
#ifndef ETHERTYPE_LLDP
#define ETHERTYPE_LLDP 0x88cc
#endif
#endif

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
void sigbus_install(void);
void sigbus_reset(void);

View File

@@ -50,8 +50,7 @@ static void scope_init(Unit *u) {
assert(u->load_state == UNIT_STUB);
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
UNIT(s)->ignore_on_isolate = true;
u->ignore_on_isolate = true;
}
static void scope_done(Unit *u) {

View File

@@ -34,6 +34,13 @@ static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_ACTIVE] = UNIT_ACTIVE
};
static void slice_init(Unit *u) {
assert(u);
assert(u->load_state == UNIT_STUB);
u->ignore_on_isolate = true;
}
static void slice_set_state(Slice *t, SliceState state) {
SliceState old_state;
assert(t);
@@ -305,6 +312,7 @@ const UnitVTable slice_vtable = {
.no_instances = true,
.can_transient = true,
.init = slice_init,
.load = slice_load,
.coldplug = slice_coldplug,

View File

@@ -355,10 +355,12 @@ static int raw_pull_make_local_copy(RawPull *i) {
r = copy_file_atomic(i->settings_path, local_settings, 0644, i->force_local, 0);
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r < 0 && r != -ENOENT)
else if (r == -ENOENT)
log_debug_errno(r, "Skipping creation of settings file, since none was found.");
else if (r < 0)
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
else
log_info("Created new settings file '%s.nspawn'", i->local);
log_info("Created new settings file %s.", local_settings);
}
return 0;

View File

@@ -251,10 +251,12 @@ static int tar_pull_make_local_copy(TarPull *i) {
r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0);
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r < 0 && r != -ENOENT)
else if (r == -ENOENT)
log_debug_errno(r, "Skipping creation of settings file, since none was found.");
else if (r < 0)
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
else
log_info("Created new settings file '%s.nspawn'", i->local);
log_info("Created new settings file %s.", local_settings);
}
return 0;

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sd-event.h"
#include "journal-remote-write.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "journal-file.h"
typedef struct RemoteServer RemoteServer;

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sd-event.h"
#include "hashmap.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <microhttpd.h>
#include <stdarg.h>

View File

@@ -42,10 +42,10 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload,
uint8_t code, size_t optlen, const void *optval);
typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
const void *option, void *userdata);
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message);
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
uint8_t type, uint16_t arp_type, size_t optlen,

View File

@@ -135,7 +135,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
}
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
uint8_t *message_type, char **error_message, dhcp_option_cb_t cb,
uint8_t *message_type, char **error_message, dhcp_option_callback_t cb,
void *userdata) {
uint8_t code, len;
const uint8_t *option;
@@ -221,7 +221,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
return 0;
}
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) {
int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) {
_cleanup_free_ char *error_message = NULL;
uint8_t overload = 0;
uint8_t message_type = 0;

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sd-dhcp-server.h"
#include "sd-event.h"

View File

@@ -1,360 +0,0 @@
/***
This file is part of systemd.
Copyright (C) 2014 Tom Gundersen
Copyright (C) 2014 Susant Sahani
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-lldp.h"
#include "alloc-util.h"
#include "lldp-internal.h"
/* We store maximum 1K chassis entries */
#define LLDP_MIB_MAX_CHASSIS 1024
/* Maximum Ports can be attached to any chassis */
#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32
/* 10.5.5.2.2 mibUpdateObjects ()
* The mibUpdateObjects () procedure updates the MIB objects corresponding to
* the TLVs contained in the received LLDPDU for the LLDP remote system
* indicated by the LLDP remote systems update process defined in 10.3.5 */
int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
lldp_neighbour_port *p;
uint16_t length, ttl;
uint8_t *data;
uint8_t type;
int r;
assert_return(c, -EINVAL);
assert_return(tlv, -EINVAL);
r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
/* Update the packet if we already have */
LIST_FOREACH(port, p, c->ports) {
if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) {
r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
return r;
p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
sd_lldp_packet_unref(p->packet);
p->packet = tlv;
prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx);
return 0;
}
}
return -1;
}
int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) {
lldp_neighbour_port *p, *q;
uint8_t *data;
uint16_t length;
uint8_t type;
int r;
assert_return(c, -EINVAL);
assert_return(tlv, -EINVAL);
r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
LIST_FOREACH_SAFE(port, p, q, c->ports) {
/* Find the port */
if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) {
lldp_neighbour_port_remove_and_free(p);
break;
}
}
return 0;
}
int lldp_mib_add_objects(Prioq *by_expiry,
Hashmap *neighbour_mib,
tlv_packet *tlv) {
_cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
_cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
lldp_chassis_id chassis_id;
bool new_chassis = false;
uint8_t subtype, *data;
uint16_t ttl, length;
int r;
assert_return(by_expiry, -EINVAL);
assert_return(neighbour_mib, -EINVAL);
assert_return(tlv, -EINVAL);
r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length);
if (r < 0)
goto drop;
r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
goto drop;
/* Make hash key */
chassis_id.type = subtype;
chassis_id.length = length;
chassis_id.data = data;
/* Try to find the Chassis */
c = hashmap_get(neighbour_mib, &chassis_id);
if (!c) {
/* Don't create chassis if ttl 0 is received . Silently drop it */
if (ttl == 0) {
log_lldp("TTL value 0 received. Skiping Chassis creation.");
goto drop;
}
/* Admission Control: Can we store this packet ? */
if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) {
log_lldp("Exceeding number of chassie: %d. Dropping ...",
hashmap_size(neighbour_mib));
goto drop;
}
r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c);
if (r < 0)
goto drop;
new_chassis = true;
r = hashmap_put(neighbour_mib, &c->chassis_id, c);
if (r < 0)
goto drop;
} else {
/* When the TTL field is set to zero, the receiving LLDP agent is notified all
* system information associated with the LLDP agent/port is to be deleted */
if (ttl == 0) {
log_lldp("TTL value 0 received . Deleting associated Port ...");
lldp_mib_remove_objects(c, tlv);
c = NULL;
goto drop;
}
/* if we already have this port just update it */
r = lldp_mib_update_objects(c, tlv);
if (r >= 0) {
c = NULL;
return r;
}
/* Admission Control: Can this port attached to the existing chassis ? */
if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) {
log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref);
c = NULL;
goto drop;
}
}
/* This is a new port */
r = lldp_neighbour_port_new(c, tlv, &p);
if (r < 0)
goto drop;
r = prioq_put(c->by_expiry, p, &p->prioq_idx);
if (r < 0)
goto drop;
/* Attach new port to chassis */
LIST_PREPEND(port, c->ports, p);
c->n_ref ++;
p = NULL;
c = NULL;
return 0;
drop:
sd_lldp_packet_unref(tlv);
if (new_chassis)
hashmap_remove(neighbour_mib, &c->chassis_id);
return r;
}
void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) {
lldp_chassis *c;
assert(p);
assert(p->c);
c = p->c;
prioq_remove(c->by_expiry, p, &p->prioq_idx);
LIST_REMOVE(port, c->ports, p);
lldp_neighbour_port_free(p);
/* Drop the Chassis if no port is attached */
c->n_ref --;
if (c->n_ref <= 1) {
hashmap_remove(c->neighbour_mib, &c->chassis_id);
lldp_chassis_free(c);
}
}
void lldp_neighbour_port_free(lldp_neighbour_port *p) {
if(!p)
return;
sd_lldp_packet_unref(p->packet);
free(p->data);
free(p);
}
int lldp_neighbour_port_new(lldp_chassis *c,
tlv_packet *tlv,
lldp_neighbour_port **ret) {
_cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
uint16_t length, ttl;
uint8_t *data;
uint8_t type;
int r;
assert(tlv);
r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
if (r < 0)
return r;
r = sd_lldp_packet_read_ttl(tlv, &ttl);
if (r < 0)
return r;
p = new0(lldp_neighbour_port, 1);
if (!p)
return -ENOMEM;
p->c = c;
p->type = type;
p->length = length;
p->packet = tlv;
p->prioq_idx = PRIOQ_IDX_NULL;
p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
p->data = memdup(data, length);
if (!p->data)
return -ENOMEM;
*ret = p;
p = NULL;
return 0;
}
void lldp_chassis_free(lldp_chassis *c) {
if (!c)
return;
if (c->n_ref > 1)
return;
free(c->chassis_id.data);
free(c);
}
int lldp_chassis_new(tlv_packet *tlv,
Prioq *by_expiry,
Hashmap *neighbour_mib,
lldp_chassis **ret) {
_cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
uint16_t length;
uint8_t *data;
uint8_t type;
int r;
assert(tlv);
r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length);
if (r < 0)
return r;
c = new0(lldp_chassis, 1);
if (!c)
return -ENOMEM;
c->n_ref = 1;
c->chassis_id.type = type;
c->chassis_id.length = length;
c->chassis_id.data = memdup(data, length);
if (!c->chassis_id.data)
return -ENOMEM;
LIST_HEAD_INIT(c->ports);
c->by_expiry = by_expiry;
c->neighbour_mib = neighbour_mib;
*ret = c;
c = NULL;
return 0;
}
int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
_cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL;
tlv_packet *p;
uint16_t length;
int r;
assert(fd);
assert(userdata);
r = tlv_packet_new(&packet);
if (r < 0)
return r;
length = read(fd, &packet->pdu, sizeof(packet->pdu));
/* Silently drop the packet */
if ((size_t) length > ETHER_MAX_LEN)
return 0;
packet->userdata = userdata;
p = packet;
packet = NULL;
return lldp_handle_packet(p, (uint16_t) length);
}

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -18,74 +20,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sd-event.h"
#include "sd-lldp.h"
#include "list.h"
#include "lldp-tlv.h"
#include "hashmap.h"
#include "log.h"
#include "prioq.h"
typedef struct lldp_neighbour_port lldp_neighbour_port;
typedef struct lldp_chassis lldp_chassis;
typedef struct lldp_chassis_id lldp_chassis_id;
typedef struct lldp_agent_statistics lldp_agent_statistics;
struct sd_lldp {
int ifindex;
int fd;
struct lldp_neighbour_port {
uint8_t type;
uint8_t *data;
sd_event *event;
int64_t event_priority;
sd_event_source *io_event_source;
sd_event_source *timer_event_source;
uint16_t length;
usec_t until;
Prioq *neighbor_by_expiry;
Hashmap *neighbor_by_id;
unsigned prioq_idx;
uint64_t neighbors_max;
lldp_chassis *c;
tlv_packet *packet;
sd_lldp_callback_t callback;
void *userdata;
LIST_FIELDS(lldp_neighbour_port, port);
uint16_t capability_mask;
struct ether_addr filter_address;
};
int lldp_neighbour_port_new(lldp_chassis *c, tlv_packet *tlv, lldp_neighbour_port **ret);
void lldp_neighbour_port_free(lldp_neighbour_port *p);
void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p);
DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_neighbour_port *, lldp_neighbour_port_free);
#define _cleanup_lldp_neighbour_port_free_ _cleanup_(lldp_neighbour_port_freep)
struct lldp_chassis_id {
uint8_t type;
uint16_t length;
uint8_t *data;
};
struct lldp_chassis {
unsigned n_ref;
lldp_chassis_id chassis_id;
Prioq *by_expiry;
Hashmap *neighbour_mib;
LIST_HEAD(lldp_neighbour_port, ports);
};
int lldp_chassis_new(tlv_packet *tlv,
Prioq *by_expiry,
Hashmap *neighbour_mib,
lldp_chassis **ret);
void lldp_chassis_free(lldp_chassis *c);
DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_chassis *, lldp_chassis_free);
#define _cleanup_lldp_chassis_free_ _cleanup_(lldp_chassis_freep)
int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv);
int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv);
int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv);
int lldp_handle_packet(tlv_packet *m, uint16_t length);
int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata);
#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__)

View File

@@ -0,0 +1,792 @@
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "alloc-util.h"
#include "escape.h"
#include "ether-addr-util.h"
#include "hexdecoct.h"
#include "in-addr-util.h"
#include "lldp-internal.h"
#include "lldp-neighbor.h"
#include "lldp.h"
#include "unaligned.h"
static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
const LLDPNeighborID *id = p;
siphash24_compress(id->chassis_id, id->chassis_id_size, state);
siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
siphash24_compress(id->port_id, id->port_id_size, state);
siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state);
}
static int lldp_neighbor_id_compare_func(const void *a, const void *b) {
const LLDPNeighborID *x = a, *y = b;
int r;
r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size));
if (r != 0)
return r;
if (x->chassis_id_size < y->chassis_id_size)
return -1;
if (x->chassis_id_size > y->chassis_id_size)
return 1;
r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size));
if (r != 0)
return r;
if (x->port_id_size < y->port_id_size)
return -1;
if (x->port_id_size > y->port_id_size)
return 1;
return 0;
}
const struct hash_ops lldp_neighbor_id_hash_ops = {
.hash = lldp_neighbor_id_hash_func,
.compare = lldp_neighbor_id_compare_func
};
int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
const sd_lldp_neighbor *x = a, *y = b;
if (x->until < y->until)
return -1;
if (x->until > y->until)
return 1;
return 0;
}
_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
if (!n)
return NULL;
assert(n->n_ref > 0 || n->lldp);
n->n_ref++;
return n;
}
static void lldp_neighbor_free(sd_lldp_neighbor *n) {
assert(n);
free(n->id.port_id);
free(n->id.chassis_id);
free(n->port_description);
free(n->system_name);
free(n->system_description);
free(n->chassis_id_as_string);
free(n->port_id_as_string);
free(n);
}
_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
/* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from
* the sd_lldp object. */
if (!n)
return NULL;
assert(n->n_ref > 0);
n->n_ref--;
if (n->n_ref <= 0 && !n->lldp)
lldp_neighbor_free(n);
return NULL;
}
sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) {
/* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */
if (!n)
return NULL;
if (!n->lldp)
return NULL;
assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n);
assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0);
n->lldp = NULL;
if (n->n_ref <= 0)
lldp_neighbor_free(n);
return NULL;
}
sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) {
sd_lldp_neighbor *n;
n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size);
if (!n)
return NULL;
n->raw_size = raw_size;
n->n_ref = 1;
return n;
}
static int parse_string(char **s, const void *q, size_t n) {
const char *p = q;
char *k;
assert(s);
assert(p || n == 0);
if (*s) {
log_lldp("Found duplicate string, ignoring field.");
return 0;
}
/* Strip trailing NULs, just to be nice */
while (n > 0 && p[n-1] == 0)
n--;
if (n <= 0) /* Ignore empty strings */
return 0;
/* Look for inner NULs */
if (memchr(p, 0, n)) {
log_lldp("Found inner NUL in string, ignoring field.");
return 0;
}
/* Let's escape weird chars, for security reasons */
k = cescape_length(p, n);
if (!k)
return -ENOMEM;
free(*s);
*s = k;
return 1;
}
int lldp_neighbor_parse(sd_lldp_neighbor *n) {
struct ether_header h;
const uint8_t *p;
size_t left;
int r;
assert(n);
if (n->raw_size < sizeof(struct ether_header)) {
log_lldp("Recieved truncated packet, ignoring.");
return -EBADMSG;
}
memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h));
if (h.ether_type != htobe16(ETHERTYPE_LLDP)) {
log_lldp("Received packet with wrong type, ignoring.");
return -EBADMSG;
}
if (h.ether_dhost[0] != 0x01 ||
h.ether_dhost[1] != 0x80 ||
h.ether_dhost[2] != 0xc2 ||
h.ether_dhost[3] != 0x00 ||
h.ether_dhost[4] != 0x00 ||
!IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) {
log_lldp("Received packet with wrong destination address, ignoring.");
return -EBADMSG;
}
memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr));
memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr));
p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header);
left = n->raw_size - sizeof(struct ether_header);
for (;;) {
uint8_t type;
uint16_t length;
if (left < 2) {
log_lldp("TLV lacks header, ignoring.");
return -EBADMSG;
}
type = p[0] >> 1;
length = p[1] + (((uint16_t) (p[0] & 1)) << 8);
p += 2, left -= 2;
if (left < length) {
log_lldp("TLV truncated, ignoring datagram.");
return -EBADMSG;
}
switch (type) {
case LLDP_TYPE_END:
if (length != 0) {
log_lldp("End marker TLV not zero-sized, ignoring datagram.");
return -EBADMSG;
}
if (left != 0) {
log_lldp("Trailing garbage in datagram, ignoring datagram.");
return -EBADMSG;
}
goto end_marker;
case LLDP_TYPE_CHASSIS_ID:
if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */
log_lldp("Chassis ID field size out of range, ignoring datagram.");
return -EBADMSG;
}
if (n->id.chassis_id) {
log_lldp("Duplicate chassis ID field, ignoring datagram.");
return -EBADMSG;
}
n->id.chassis_id = memdup(p, length);
if (!n->id.chassis_id)
return -ENOMEM;
n->id.chassis_id_size = length;
break;
case LLDP_TYPE_PORT_ID:
if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */
log_lldp("Port ID field size out of range, ignoring datagram.");
return -EBADMSG;
}
if (n->id.port_id) {
log_lldp("Duplicate port ID field, ignoring datagram.");
return -EBADMSG;
}
n->id.port_id = memdup(p, length);
if (!n->id.port_id)
return -ENOMEM;
n->id.port_id_size = length;
break;
case LLDP_TYPE_TTL:
if (length != 2) {
log_lldp("TTL field has wrong size, ignoring datagram.");
return -EBADMSG;
}
if (n->has_ttl) {
log_lldp("Duplicate TTL field, ignoring datagram.");
return -EBADMSG;
}
n->ttl = unaligned_read_be16(p);
n->has_ttl = true;
break;
case LLDP_TYPE_PORT_DESCRIPTION:
r = parse_string(&n->port_description, p, length);
if (r < 0)
return r;
break;
case LLDP_TYPE_SYSTEM_NAME:
r = parse_string(&n->system_name, p, length);
if (r < 0)
return r;
break;
case LLDP_TYPE_SYSTEM_DESCRIPTION:
r = parse_string(&n->system_description, p, length);
if (r < 0)
return r;
break;
case LLDP_TYPE_SYSTEM_CAPABILITIES:
if (length != 4)
log_lldp("System capabilities field has wrong size, ignoring.");
else {
n->system_capabilities = unaligned_read_be16(p);
n->enabled_capabilities = unaligned_read_be16(p + 2);
n->has_capabilities = true;
}
break;
case LLDP_TYPE_PRIVATE:
if (length < 4)
log_lldp("Found private TLV that is too short, ignoring.");
break;
}
p += length, left -= length;
}
end_marker:
if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) {
log_lldp("One or more mandatory TLV missing in datagram. Ignoring.");
return -EBADMSG;
}
n->rindex = sizeof(struct ether_header);
return 0;
}
void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
assert(n);
if (n->ttl > 0)
n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC);
else
n->until = 0;
if (n->lldp)
prioq_reshuffle(n->lldp->neighbor_by_expiry, n, &n->prioq_idx);
}
bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) {
if (a == b)
return true;
if (!a || !b)
return false;
if (a->raw_size != b->raw_size)
return false;
return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0;
}
_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
assert_return(n, -EINVAL);
assert_return(address, -EINVAL);
*address = n->source_address;
return 0;
}
_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
assert_return(n, -EINVAL);
assert_return(address, -EINVAL);
*address = n->destination_address;
return 0;
}
_public_ 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;
}
_public_ 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);
assert_return(ret, -EINVAL);
assert_return(size, -EINVAL);
assert(n->id.chassis_id_size > 0);
*type = *(uint8_t*) n->id.chassis_id;
*ret = (uint8_t*) n->id.chassis_id + 1;
*size = n->id.chassis_id_size - 1;
return 0;
}
static int format_mac_address(const void *data, size_t sz, char **ret) {
struct ether_addr a;
char *k;
assert(data || sz <= 0);
if (sz != 7)
return 0;
memcpy(&a, (uint8_t*) data + 1, sizeof(a));
k = new(char, ETHER_ADDR_TO_STRING_MAX);
if (!k)
return -ENOMEM;
*ret = ether_addr_to_string(&a, k);
return 1;
}
static int format_network_address(const void *data, size_t sz, char **ret) {
union in_addr_union a;
int family;
if (sz == 6 && ((uint8_t*) data)[1] == 1) {
memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in));
family = AF_INET;
} else if (sz == 18 && ((uint8_t*) data)[1] == 2) {
memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6));
family = AF_INET6;
} else
return 0;
return in_addr_to_string(family, &a, ret);
}
_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
char *k;
int r;
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
if (n->chassis_id_as_string) {
*ret = n->chassis_id_as_string;
return 0;
}
assert(n->id.chassis_id_size > 0);
switch (*(uint8_t*) n->id.chassis_id) {
case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT:
case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
case LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT:
case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME:
case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED:
k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1);
if (!k)
return -ENOMEM;
goto done;
case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k);
if (r < 0)
return r;
if (r > 0)
goto done;
break;
case LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS:
r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k);
if (r < 0)
return r;
if (r > 0)
goto done;
break;
}
/* Generic fallback */
k = hexmem(n->id.chassis_id, n->id.chassis_id_size);
if (!k)
return -ENOMEM;
done:
*ret = n->chassis_id_as_string = k;
return 0;
}
_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
assert_return(n, -EINVAL);
assert_return(type, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(size, -EINVAL);
assert(n->id.port_id_size > 0);
*type = *(uint8_t*) n->id.port_id;
*ret = (uint8_t*) n->id.port_id + 1;
*size = n->id.port_id_size - 1;
return 0;
}
_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
char *k;
int r;
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
if (n->port_id_as_string) {
*ret = n->port_id_as_string;
return 0;
}
assert(n->id.port_id_size > 0);
switch (*(uint8_t*) n->id.port_id) {
case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1);
if (!k)
return -ENOMEM;
goto done;
case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
r = format_mac_address(n->id.port_id, n->id.port_id_size, &k);
if (r < 0)
return r;
if (r > 0)
goto done;
break;
case LLDP_PORT_SUBTYPE_NETWORK_ADDRESS:
r = format_network_address(n->id.port_id, n->id.port_id_size, &k);
if (r < 0)
return r;
if (r > 0)
goto done;
break;
}
/* Generic fallback */
k = hexmem(n->id.port_id, n->id.port_id_size);
if (!k)
return -ENOMEM;
done:
*ret = n->port_id_as_string = k;
return 0;
}
_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
*ret = n->ttl;
return 0;
}
_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
if (!n->system_name)
return -ENODATA;
*ret = n->system_name;
return 0;
}
_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
if (!n->system_description)
return -ENODATA;
*ret = n->system_description;
return 0;
}
_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
if (!n->port_description)
return -ENODATA;
*ret = n->port_description;
return 0;
}
_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
if (!n->has_capabilities)
return -ENODATA;
*ret = n->system_capabilities;
return 0;
}
_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
if (!n->has_capabilities)
return -ENODATA;
*ret = n->enabled_capabilities;
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(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
r = lldp_neighbor_parse(n);
if (r < 0)
return r;
*ret = n;
n = 0;
return r;
}
_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
assert_return(n, -EINVAL);
assert(n->raw_size >= sizeof(struct ether_header));
n->rindex = sizeof(struct ether_header);
return 0;
}
_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
size_t length;
assert_return(n, -EINVAL);
if (n->rindex == n->raw_size) /* EOF */
return -ESPIPE;
if (n->rindex + 2 > n->raw_size) /* Truncated message */
return -EBADMSG;
length = LLDP_NEIGHBOR_LENGTH(n);
if (n->rindex + 2 + length > n->raw_size)
return -EBADMSG;
n->rindex += 2 + length;
return n->rindex < n->raw_size;
}
_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
assert_return(n, -EINVAL);
assert_return(type, -EINVAL);
if (n->rindex == n->raw_size) /* EOF */
return -ESPIPE;
if (n->rindex + 2 > n->raw_size)
return -EBADMSG;
*type = LLDP_NEIGHBOR_TYPE(n);
return 0;
}
_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
uint8_t k;
int r;
assert_return(n, -EINVAL);
r = sd_lldp_neighbor_tlv_get_type(n, &k);
if (r < 0)
return r;
return type == k;
}
_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype) {
const uint8_t *d;
size_t length;
int r;
assert_return(n, -EINVAL);
assert_return(oui, -EINVAL);
assert_return(subtype, -EINVAL);
r = sd_lldp_neighbor_tlv_is_type(n, LLDP_TYPE_PRIVATE);
if (r < 0)
return r;
if (r == 0)
return -ENXIO;
length = LLDP_NEIGHBOR_LENGTH(n);
if (length < 4)
return -EBADMSG;
if (n->rindex + 2 + length > n->raw_size)
return -EBADMSG;
d = LLDP_NEIGHBOR_DATA(n);
memcpy(oui, d, 3);
*subtype = d[3];
return 0;
}
_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype) {
uint8_t k[3], st;
int r;
r = sd_lldp_neighbor_tlv_get_oui(n, k, &st);
if (r == -ENXIO)
return 0;
if (r < 0)
return r;
return memcmp(k, oui, 3) == 0 && st == subtype;
}
_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
size_t length;
assert_return(n, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(size, -EINVAL);
/* Note that this returns the full TLV, including the TLV header */
if (n->rindex + 2 > n->raw_size)
return -EBADMSG;
length = LLDP_NEIGHBOR_LENGTH(n);
if (n->rindex + 2 + length > n->raw_size)
return -EBADMSG;
*ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
*size = length + 2;
return 0;
}

View File

@@ -0,0 +1,106 @@
#pragma once
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <inttypes.h>
#include <stdbool.h>
#include <sys/types.h>
#include "sd-lldp.h"
#include "hash-funcs.h"
#include "lldp-internal.h"
#include "time-util.h"
typedef struct LLDPNeighborID {
/* The spec calls this an "MSAP identifier" */
void *chassis_id;
size_t chassis_id_size;
void *port_id;
size_t port_id_size;
} LLDPNeighborID;
struct sd_lldp_neighbor {
/* Neighbor objects stay around as long as they are linked into an "sd_lldp" object or n_ref > 0. */
sd_lldp *lldp;
unsigned n_ref;
usec_t until;
unsigned prioq_idx;
struct ether_addr source_address;
struct ether_addr destination_address;
LLDPNeighborID id;
/* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */
size_t raw_size;
/* The current read index for the iterative TLV interface */
size_t rindex;
/* And a couple of fields parsed out. */
bool has_ttl:1;
bool has_capabilities:1;
bool has_port_vlan_id:1;
uint16_t ttl;
uint16_t system_capabilities;
uint16_t enabled_capabilities;
char *port_description;
char *system_name;
char *system_description;
uint16_t port_vlan_id;
char *chassis_id_as_string;
char *port_id_as_string;
};
static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) {
return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor));
}
static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) {
return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1;
}
static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) {
uint8_t *p;
p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
return p[1] + (((size_t) (p[0] & 1)) << 8);
}
static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) {
return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
}
extern const struct hash_ops lldp_neighbor_id_hash_ops;
int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n);
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);

View File

@@ -22,62 +22,55 @@
#include <netinet/if_ether.h>
#include "fd-util.h"
#include "lldp-internal.h"
#include "lldp-network.h"
#include "lldp-tlv.h"
#include "socket-util.h"
int lldp_network_bind_raw_socket(int ifindex) {
typedef struct LLDPFrame {
struct ethhdr hdr;
uint8_t tlvs[0];
} LLDPFrame;
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest)), /* A <- 4 bytes of destination MAC */
static const struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_proto)), /* A <- protocol */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */
};
struct sock_fprog fprog = {
static const struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
.filter = filter
.filter = (struct sock_filter*) filter,
};
_cleanup_close_ int s = -1;
union sockaddr_union saddrll = {
.ll.sll_family = AF_PACKET,
.ll.sll_ifindex = ifindex,
};
_cleanup_close_ int fd = -1;
int r;
assert(ifindex > 0);
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0)
fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP));
if (fd < 0)
return -errno;
r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
if (r < 0)
return -errno;
r = bind(s, &saddrll.sa, sizeof(saddrll.ll));
r = bind(fd, &saddrll.sa, sizeof(saddrll.ll));
if (r < 0)
return -errno;
r = s;
s = -1;
r = fd;
fd = -1;
return r;
}

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sd-event.h"
int lldp_network_bind_raw_socket(int ifindex);

View File

@@ -1,116 +0,0 @@
/***
This file is part of systemd.
Copyright (C) 2014 Tom Gundersen
Copyright (C) 2014 Susant Sahani
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "alloc-util.h"
#include "async.h"
#include "lldp-internal.h"
#include "lldp-network.h"
#include "lldp-port.h"
int lldp_port_start(lldp_port *p) {
int r;
assert_return(p, -EINVAL);
r = lldp_network_bind_raw_socket(p->ifindex);
if (r < 0)
return r;
p->rawfd = r;
r = sd_event_add_io(p->event, &p->lldp_port_rx,
p->rawfd, EPOLLIN, lldp_receive_packet, p);
if (r < 0) {
log_debug_errno(r, "Failed to allocate event source: %m");
goto fail;
}
r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority);
if (r < 0) {
log_debug_errno(r, "Failed to set event priority: %m");
goto fail;
}
r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx");
if (r < 0) {
log_debug_errno(r, "Failed to set event name: %m");
goto fail;
}
return 0;
fail:
lldp_port_stop(p);
return r;
}
int lldp_port_stop(lldp_port *p) {
assert_return(p, -EINVAL);
p->rawfd = asynchronous_close(p->rawfd);
p->lldp_port_rx = sd_event_source_unref(p->lldp_port_rx);
return 0;
}
void lldp_port_free(lldp_port *p) {
if (!p)
return;
lldp_port_stop(p);
free(p->ifname);
free(p);
}
int lldp_port_new(int ifindex,
const char *ifname,
const struct ether_addr *addr,
void *userdata,
lldp_port **ret) {
_cleanup_free_ lldp_port *p = NULL;
assert_return(ifindex, -EINVAL);
assert_return(ifname, -EINVAL);
assert_return(addr, -EINVAL);
p = new0(lldp_port, 1);
if (!p)
return -ENOMEM;
p->rawfd = -1;
p->ifindex = ifindex;
p->ifname = strdup(ifname);
if (!p->ifname)
return -ENOMEM;
memcpy(&p->mac, addr, ETH_ALEN);
p->userdata = userdata;
*ret = p;
p = NULL;
return 0;
}

View File

@@ -1,69 +0,0 @@
/***
This file is part of systemd.
Copyright (C) 2014 Tom Gundersen
Copyright (C) 2014 Susant Sahani
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <net/ethernet.h>
#include "sd-event.h"
#include "sd-lldp.h"
#include "util.h"
typedef struct lldp_port lldp_port;
typedef enum LLDPPortStatus {
LLDP_PORT_STATUS_NONE,
LLDP_PORT_STATUS_ENABLED,
LLDP_PORT_STATUS_DISABLED,
_LLDP_PORT_STATUS_MAX,
_LLDP_PORT_STATUS_INVALID = -1,
} LLDPPortStatus;
struct lldp_port {
LLDPPortStatus status;
int ifindex;
char *ifname;
struct ether_addr mac;
int rawfd;
sd_event *event;
sd_event_source *lldp_port_rx;
int event_priority;
void *userdata;
};
int lldp_port_new(int ifindex,
const char *ifname,
const struct ether_addr *addr,
void *userdata,
lldp_port **ret);
void lldp_port_free(lldp_port *p);
DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_port*, lldp_port_free);
#define _cleanup_lldp_port_free_ _cleanup_(lldp_port_freep)
int lldp_port_start(lldp_port *p);
int lldp_port_stop(lldp_port *p);

View File

@@ -1,638 +0,0 @@
/***
This file is part of systemd.
Copyright (C) 2014 Tom Gundersen
Copyright (C) 2014 Susant Sahani
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <arpa/inet.h>
#include <net/ethernet.h>
#include "alloc-util.h"
#include "lldp-tlv.h"
#include "macro.h"
int tlv_section_new(tlv_section **ret) {
tlv_section *s;
s = new0(tlv_section, 1);
if (!s)
return -ENOMEM;
*ret = s;
return 0;
}
void tlv_section_free(tlv_section *m) {
if (!m)
return;
free(m);
}
int tlv_packet_new(tlv_packet **ret) {
tlv_packet *m;
m = new0(tlv_packet, 1);
if (!m)
return -ENOMEM;
LIST_HEAD_INIT(m->sections);
m->n_ref = 1;
*ret = m;
return 0;
}
tlv_packet *sd_lldp_packet_ref(tlv_packet *m) {
if (!m)
return NULL;
assert(m->n_ref > 0);
m->n_ref++;
return m;
}
tlv_packet *sd_lldp_packet_unref(tlv_packet *m) {
tlv_section *s, *n;
if (!m)
return NULL;
assert(m->n_ref > 0);
m->n_ref--;
if (m->n_ref > 0)
return m;
LIST_FOREACH_SAFE(section, s, n, m->sections)
tlv_section_free(s);
free(m);
return NULL;
}
int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) {
uint8_t *p;
assert_return(m, -EINVAL);
assert_return(data, -EINVAL);
assert_return(data_length, -EINVAL);
if (m->length + data_length > ETHER_MAX_LEN)
return -ENOMEM;
p = m->pdu + m->length;
memcpy(p, data, data_length);
m->length += data_length;
return 0;
}
int tlv_packet_append_u8(tlv_packet *m, uint8_t data) {
assert_return(m, -EINVAL);
return tlv_packet_append_bytes(m, &data, sizeof(uint8_t));
}
int tlv_packet_append_u16(tlv_packet *m, uint16_t data) {
uint16_t type;
assert_return(m, -EINVAL);
type = htons(data);
return tlv_packet_append_bytes(m, &type, sizeof(uint16_t));
}
int tlv_packet_append_u32(tlv_packet *m, uint32_t data) {
uint32_t type;
assert_return(m, -EINVAL);
type = htonl(data);
return tlv_packet_append_bytes(m, &type, sizeof(uint32_t));
}
int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) {
assert_return(m, -EINVAL);
return tlv_packet_append_bytes(m, data, size);
}
int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) {
assert_return(m, -EINVAL);
m->container_pos = m->pdu + m->length;
return tlv_packet_append_u16(m, type << 9);
}
int lldp_tlv_packet_close_container(tlv_packet *m) {
uint16_t type;
assert_return(m, -EINVAL);
assert_return(m->container_pos, -EINVAL);
memcpy(&type, m->container_pos, sizeof(uint16_t));
type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff);
memcpy(m->container_pos, &type, sizeof(uint16_t));
return 0;
}
static inline int tlv_packet_read_internal(tlv_section *m, void **data) {
assert_return(m->read_pos, -EINVAL);
*data = m->read_pos;
return 0;
}
int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) {
void *val = NULL;
int r;
assert_return(m, -EINVAL);
r = tlv_packet_read_internal(m->container, &val);
if (r < 0)
return r;
memcpy(data, val, sizeof(uint8_t));
m->container->read_pos ++;
return 0;
}
int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) {
uint16_t t;
void *val = NULL;
int r;
assert_return(m, -EINVAL);
r = tlv_packet_read_internal(m->container, &val);
if (r < 0)
return r;
memcpy(&t, val, sizeof(uint16_t));
*data = ntohs(t);
m->container->read_pos += 2;
return 0;
}
int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) {
uint32_t t;
void *val;
int r;
assert_return(m, -EINVAL);
r = tlv_packet_read_internal(m->container, &val);
if (r < 0)
return r;
memcpy(&t, val, sizeof(uint32_t));
*data = ntohl(t);
m->container->read_pos += 4;
return r;
}
int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
void *val = NULL;
int r;
assert_return(m, -EINVAL);
r = tlv_packet_read_internal(m->container, &val);
if (r < 0)
return r;
*data = (char *) val;
*data_length = m->container->data + m->container->length - m->container->read_pos;
m->container->read_pos += *data_length;
return 0;
}
int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) {
void *val = NULL;
int r;
assert_return(m, -EINVAL);
r = tlv_packet_read_internal(m->container, &val);
if (r < 0)
return r;
*data = (uint8_t *) val;
*data_length = m->container->data + m->container->length - m->container->read_pos;
m->container->read_pos += *data_length;
return 0;
}
/* parse raw TLV packet */
int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
tlv_section *section, *tail;
uint16_t t, l;
uint8_t *p;
int r;
assert_return(m, -EINVAL);
assert_return(size, -EINVAL);
p = m->pdu;
/* extract Ethernet header */
memcpy(&m->mac, p, ETH_ALEN);
p += sizeof(struct ether_header);
for (l = 0; l <= size; ) {
r = tlv_section_new(&section);
if (r < 0)
return r;
memcpy(&t, p, sizeof(uint16_t));
section->type = ntohs(t) >> 9;
section->length = ntohs(t) & 0x01ff;
if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) {
tlv_section_free(section);
break;
}
p += 2;
if (section->type == LLDP_TYPE_PRIVATE &&
section->length >= LLDP_OUI_LEN + 1) {
section->oui = p;
p += LLDP_OUI_LEN;
section->subtype = *p++;
section->length -= LLDP_OUI_LEN + 1;
l += LLDP_OUI_LEN + 1;
}
section->data = p;
LIST_FIND_TAIL(section, m->sections, tail);
LIST_INSERT_AFTER(section, m->sections, tail, section);
p += section->length;
l += (section->length + 2);
}
return 0;
}
int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) {
tlv_section *s;
assert_return(m, -EINVAL);
assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL);
LIST_FOREACH(section, s, m->sections)
if (s->type == type)
break;
if (!s)
return -1;
m->container = s;
m->container->read_pos = s->data;
if (!m->container->read_pos) {
m->container = NULL;
return -1;
}
return 0;
}
int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) {
tlv_section *s;
assert_return(m, -EINVAL);
assert_return(oui, -EINVAL);
LIST_FOREACH(section, s, m->sections) {
if (s->type == LLDP_TYPE_PRIVATE &&
s->oui &&
s->subtype == subtype &&
!memcmp(s->oui, oui, LLDP_OUI_LEN))
break;
}
if (!s)
return -1;
m->container = s;
m->container->read_pos = s->data;
if (!m->container->read_pos) {
m->container = NULL;
return -1;
}
return 0;
}
int lldp_tlv_packet_exit_container(tlv_packet *m) {
assert_return(m, -EINVAL);
m->container = 0;
return 0;
}
static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) {
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container(tlv, type);
if (r < 0)
return r;
r = tlv_packet_read_u16(tlv, value);
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) {
char *s;
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container(tlv, type);
if (r < 0)
return r;
r = tlv_packet_read_string(tlv, &s, length);
if (r < 0)
goto out;
*data = (char *) s;
out:
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_read_chassis_id(tlv_packet *tlv,
uint8_t *type,
uint8_t **data,
uint16_t *length) {
uint8_t subtype;
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID);
if (r < 0)
return r;
r = tlv_packet_read_u8(tlv, &subtype);
if (r < 0)
goto out;
switch (subtype) {
case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
r = tlv_packet_read_bytes(tlv, data, length);
if (r < 0)
goto out;
break;
default:
r = -EOPNOTSUPP;
break;
}
*type = subtype;
out:
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_read_port_id(tlv_packet *tlv,
uint8_t *type,
uint8_t **data,
uint16_t *length) {
uint8_t subtype;
char *s;
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID);
if (r < 0)
return r;
r = tlv_packet_read_u8(tlv, &subtype);
if (r < 0)
goto out;
switch (subtype) {
case LLDP_PORT_SUBTYPE_PORT_COMPONENT:
case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
r = tlv_packet_read_string(tlv, &s, length);
if (r < 0)
goto out;
*data = (uint8_t *) s;
break;
case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
r = tlv_packet_read_bytes(tlv, data, length);
if (r < 0)
goto out;
break;
default:
r = -EOPNOTSUPP;
break;
}
*type = subtype;
out:
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) {
return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl);
}
int sd_lldp_packet_read_system_name(tlv_packet *tlv,
char **data,
uint16_t *length) {
return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length);
}
int sd_lldp_packet_read_system_description(tlv_packet *tlv,
char **data,
uint16_t *length) {
return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length);
}
int sd_lldp_packet_read_port_description(tlv_packet *tlv,
char **data,
uint16_t *length) {
return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length);
}
int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) {
return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data);
}
int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) {
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID);
if (r < 0)
return r;
r = tlv_packet_read_u16(tlv, id);
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) {
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID);
if (r < 0)
return r;
r = tlv_packet_read_u8(tlv, flags);
if (r >= 0)
r = tlv_packet_read_u16(tlv, id);
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) {
int r, r2;
uint8_t len = 0;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME);
if (r < 0)
return r;
r = tlv_packet_read_u16(tlv, vlan_id);
if (r >= 0)
r = tlv_packet_read_u8(tlv, &len);
if (r >= 0)
r = tlv_packet_read_string(tlv, name, length);
if (r >= 0 && len < *length)
*length = len;
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) {
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID);
if (r < 0)
return r;
r = tlv_packet_read_u16(tlv, id);
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) {
int r, r2;
assert_return(tlv, -EINVAL);
r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION);
if (r < 0)
return r;
r = tlv_packet_read_u8(tlv, status);
if (r >= 0)
r = tlv_packet_read_u32(tlv, id);
r2 = lldp_tlv_packet_exit_container(tlv);
return r < 0 ? r : r2;
}
int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) {
assert_return(tlv, -EINVAL);
assert_return(dest, -EINVAL);
/* 802.1AB-2009, Table 7-1 */
if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN))
*dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE;
else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN))
*dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE;
else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN))
*dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE;
else
return -EINVAL;
return 0;
}

View File

@@ -1,94 +0,0 @@
/***
This file is part of systemd.
Copyright (C) 2014 Tom Gundersen
Copyright (C) 2014 Susant Sahani
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <net/ethernet.h>
#include "sd-lldp.h"
#include "list.h"
#include "lldp.h"
#include "util.h"
typedef struct sd_lldp_packet tlv_packet;
typedef struct sd_lldp_section tlv_section;
#define LLDP_OUI_LEN 3
struct sd_lldp_section {
uint16_t type;
uint16_t length;
uint8_t *oui;
uint8_t subtype;
uint8_t *read_pos;
uint8_t *data;
LIST_FIELDS(tlv_section, section);
};
#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }
#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }
int tlv_section_new(tlv_section **ret);
void tlv_section_free(tlv_section *ret);
struct sd_lldp_packet {
unsigned n_ref;
uint16_t type;
uint16_t length;
usec_t ts;
uint8_t *container_pos;
uint8_t pdu[ETHER_MAX_LEN];
void *userdata;
struct ether_addr mac;
tlv_section *container;
LIST_HEAD(tlv_section, sections);
};
int tlv_packet_new(tlv_packet **ret);
int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type);
int lldp_tlv_packet_close_container(tlv_packet *m);
int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length);
int tlv_packet_append_u8(tlv_packet *m, uint8_t data);
int tlv_packet_append_u16(tlv_packet *m, uint16_t data);
int tlv_packet_append_u32(tlv_packet *m, uint32_t data);
int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size);
int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type);
int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype);
int lldp_tlv_packet_exit_container(tlv_packet *m);
int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length);
int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length);
int tlv_packet_read_u8(tlv_packet *m, uint8_t *data);
int tlv_packet_read_u16(tlv_packet *m, uint16_t *data);
int tlv_packet_read_u32(tlv_packet *m, uint32_t *data);
int tlv_packet_parse_pdu(tlv_packet *t, uint16_t size);

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -18,14 +20,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
#define ETHERTYPE_LLDP 0x88cc
/* IEEE 802.3AB Clause 9: TLV Types */
typedef enum LLDPTypes {
enum {
LLDP_TYPE_END = 0,
LLDP_TYPE_CHASSIS_ID = 1,
LLDP_TYPE_PORT_ID = 2,
@@ -36,12 +34,10 @@ typedef enum LLDPTypes {
LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
LLDP_TYPE_MGMT_ADDRESS = 8,
LLDP_TYPE_PRIVATE = 127,
_LLDP_TYPE_MAX,
_LLDP_TYPE_INVALID = -1,
} LLDPTypes;
};
/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */
typedef enum LLDPChassisSubtypes {
enum {
LLDP_CHASSIS_SUBTYPE_RESERVED = 0,
LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1,
LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2,
@@ -50,25 +46,21 @@ typedef enum LLDPChassisSubtypes {
LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7,
_LLDP_CHASSIS_SUBTYPE_MAX,
_LLDP_CHASSIS_SUBTYPE_INVALID = -1,
} LLDPChassisSubtypes;
};
/* IEEE 802.3AB Clause 9.5.3: Port subtype */
typedef enum LLDPPortSubtypes {
enum {
LLDP_PORT_SUBTYPE_RESERVED = 0,
LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1,
LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2,
LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3,
LLDP_PORT_SUBTYPE_NETWORK = 4,
LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
_LLDP_PORT_SUBTYPE_MAX,
_LLDP_PORT_SUBTYPE_INVALID = -1
} LLDPPortSubtypes;
};
typedef enum LLDPSystemCapabilities {
enum {
LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
@@ -80,47 +72,31 @@ typedef enum LLDPSystemCapabilities {
LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
_LLDP_SYSTEM_CAPABILITIES_MAX,
_LLDP_SYSTEM_CAPABILITIES_INVALID = -1,
} LLDPSystemCapabilities;
};
typedef enum LLDPMedSubtype {
LLDP_MED_SUBTYPE_RESERVED = 0,
LLDP_MED_SUBTYPE_CAPABILITIES = 1,
LLDP_MED_SUBTYPE_NETWORK_POLICY = 2,
LLDP_MED_SUBTYPE_LOCATION_ID = 3,
LLDP_MED_SUBTYPE_EXTENDED_PVMDI = 4,
LLDP_MED_SUBTYPE_INV_HWREV = 5,
LLDP_MED_SUBTYPE_INV_FWREV = 6,
LLDP_MED_SUBTYPE_INV_SWREV = 7,
LLDP_MED_SUBTYPE_INV_SERIAL = 8,
LLDP_MED_SUBTYPE_INV_MANUFACTURER = 9,
LLDP_MED_SUBTYPE_INV_MODELNAME = 10,
LLDP_MED_SUBTYPE_INV_ASSETID = 11,
_LLDP_MED_SUBTYPE_MAX,
_LLDP_MED_SUBTYPE_INVALID = -1,
} LLDPMedSubtype;
#define _LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1)
#define _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \
((uint16_t) \
(LLDP_SYSTEM_CAPABILITIES_REPEATER| \
LLDP_SYSTEM_CAPABILITIES_BRIDGE| \
LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \
LLDP_SYSTEM_CAPABILITIES_ROUTER| \
LLDP_SYSTEM_CAPABILITIES_DOCSIS| \
LLDP_SYSTEM_CAPABILITIES_CVLAN| \
LLDP_SYSTEM_CAPABILITIES_SVLAN| \
LLDP_SYSTEM_CAPABILITIES_TPMR))
typedef enum LLDPMedCapability {
LLDP_MED_CAPABILITY_CAPAPILITIES = 1 << 0,
LLDP_MED_CAPABILITY_NETWORK_POLICY = 1 << 1,
LLDP_MED_CAPABILITY_LOCATION_ID = 1 << 2,
LLDP_MED_CAPABILITY_EXTENDED_PSE = 1 << 3,
LLDP_MED_CAPABILITY_EXTENDED_PD = 1 << 4,
LLDP_MED_CAPABILITY_INVENTORY = 1 << 5,
LLDP_MED_CAPABILITY_MAX,
LLDP_MED_CAPABILITY_INVALID = -1,
} LLDPMedCapability;
#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 }
#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
enum {
LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1,
LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2,
LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3,
LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4,
LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5,
LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6,
LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7,
LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1,
LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3,
LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
};

View File

@@ -101,7 +101,7 @@ struct sd_dhcp_client {
sd_event_source *timeout_t1;
sd_event_source *timeout_t2;
sd_event_source *timeout_expire;
sd_dhcp_client_cb_t cb;
sd_dhcp_client_callback_t cb;
void *userdata;
sd_dhcp_lease *lease;
usec_t start_delay;
@@ -121,7 +121,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
uint32_t revents, void *userdata);
static void client_stop(sd_dhcp_client *client, int error);
int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb,
void *userdata) {
assert_return(client, -EINVAL);
@@ -1691,8 +1691,7 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) {
return 0;
}
int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
int priority) {
int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
int r;
assert_return(client, -EINVAL);

View File

@@ -208,8 +208,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
return 0;
}
int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
int priority) {
int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
int r;
assert_return(server, -EINVAL);

View File

@@ -64,7 +64,7 @@ struct sd_dhcp6_client {
uint8_t retransmit_count;
sd_event_source *timeout_resend;
sd_event_source *timeout_resend_expire;
sd_dhcp6_client_cb_t cb;
sd_dhcp6_client_callback_t cb;
void *userdata;
struct duid duid;
size_t duid_len;
@@ -111,7 +111,7 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) {
int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_callback_t cb, void *userdata) {
assert_return(client, -EINVAL);
client->cb = cb;
@@ -1204,7 +1204,7 @@ error:
return r;
}
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) {
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) {
int r;
assert_return(client, -EINVAL);

View File

@@ -92,7 +92,7 @@ struct sd_ipv4acd {
struct ether_addr mac_addr;
sd_event *event;
int event_priority;
sd_ipv4acd_cb_t cb;
sd_ipv4acd_callback_t cb;
void* userdata;
};
@@ -428,7 +428,7 @@ int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
return 0;
}
int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) {
int r;
assert_return(ll, -EINVAL);
@@ -447,7 +447,7 @@ int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
return 0;
}
int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) {
int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) {
assert_return(ll, -EINVAL);
ll->cb = cb;

View File

@@ -52,7 +52,7 @@ struct sd_ipv4ll {
/* External */
be32_t claimed_address;
sd_ipv4ll_cb_t cb;
sd_ipv4ll_callback_t cb;
void* userdata;
};
@@ -160,7 +160,7 @@ int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
return sd_ipv4acd_detach_event(ll->acd);
}
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) {
int r;
assert_return(ll, -EINVAL);
@@ -172,7 +172,7 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
return 0;
}
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) {
assert_return(ll, -EINVAL);
ll->cb = cb;

File diff suppressed because it is too large Load Diff

View File

@@ -166,7 +166,7 @@ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) {
}
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) {
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
int r;
assert_return(nd, -EINVAL);

View File

@@ -22,6 +22,7 @@
#include <net/ethernet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "sd-event.h"
#include "sd-lldp.h"
@@ -29,7 +30,6 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "lldp-network.h"
#include "lldp-tlv.h"
#include "lldp.h"
#include "macro.h"
#include "string-util.h"
@@ -38,211 +38,8 @@
#define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
#define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc"
static int test_fd[2];
static struct ether_addr mac_addr = {
.ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}
};
static int lldp_build_tlv_packet(tlv_packet **ret) {
_cleanup_(sd_lldp_packet_unrefp) tlv_packet *m = NULL;
const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
struct ether_header ether = {
.ether_type = htons(ETHERTYPE_LLDP),
};
/* Append Ethernet header */
memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
assert_se(tlv_packet_new(&m) >= 0);
assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
assert_se(lldp_tlv_packet_close_container(m) >= 0);
/* port name */
assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
assert_se(lldp_tlv_packet_close_container(m) >= 0);
/* ttl */
assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
assert_se(tlv_packet_append_u16(m, 170) >= 0);
assert_se(lldp_tlv_packet_close_container(m) >= 0);
/* system name */
assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
assert_se(lldp_tlv_packet_close_container(m) >= 0);
/* system descrition */
assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
assert_se(lldp_tlv_packet_close_container(m) >= 0);
/* Mark end of packet */
assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
assert_se(lldp_tlv_packet_close_container(m) >= 0);
*ret = m;
m = NULL;
return 0;
}
static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
uint8_t *p, subtype;
uint16_t length;
assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
switch (subtype) {
case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
*type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
break;
default:
assert_not_reached("Unhandled option");
}
assert_se(lldp_tlv_packet_exit_container(m) >= 0);
return 0;
}
static int lldp_parse_port_id_tlv(tlv_packet *m) {
_cleanup_free_ char *p = NULL;
char *str = NULL;
uint16_t length;
uint8_t subtype;
assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
switch (subtype) {
case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
p = strndup(str, length-1);
assert_se(p);
assert_se(streq(p, TEST_LLDP_PORT) == 1);
break;
default:
assert_not_reached("Unhandled option");
}
assert_se(lldp_tlv_packet_exit_container(m) >= 0);
return 0;
}
static int lldp_parse_system_name_tlv(tlv_packet *m) {
_cleanup_free_ char *p = NULL;
char *str = NULL;
uint16_t length;
assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
p = strndup(str, length);
assert_se(p);
assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
assert_se(lldp_tlv_packet_exit_container(m) >= 0);
return 1;
}
static int lldp_parse_system_desc_tlv(tlv_packet *m) {
_cleanup_free_ char *p = NULL;
char *str = NULL;
uint16_t length;
assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
p = strndup(str, length);
assert_se(p);
assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
assert_se(lldp_tlv_packet_exit_container(m) >= 0);
return 0;
}
static int lldp_parse_ttl_tlv(tlv_packet *m) {
uint16_t ttl;
assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
assert_se(ttl == 170);
assert_se(lldp_tlv_packet_exit_container(m) >= 0);
return 0;
}
static int lldp_get_destination_type(tlv_packet *m) {
int dest;
assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0);
assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE);
return 0;
}
static int lldp_parse_tlv_packet(tlv_packet *m, int len) {
uint8_t subtype;
assert_se(tlv_packet_parse_pdu(m, len) >= 0);
assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
assert_se(lldp_parse_port_id_tlv(m) >= 0);
assert_se(lldp_parse_system_name_tlv(m) >= 0);
assert_se(lldp_parse_ttl_tlv(m) >= 0);
assert_se(lldp_parse_system_desc_tlv(m) >= 0);
assert_se(lldp_get_destination_type(m) >= 0);
return 0;
}
static void test_parser(void) {
_cleanup_(sd_lldp_packet_unrefp) tlv_packet *tlv = NULL;
/* form a packet */
lldp_build_tlv_packet(&tlv);
/* parse the packet */
tlv_packet_parse_pdu(tlv, tlv->length);
/* verify */
lldp_parse_tlv_packet(tlv, tlv->length);
}
static int test_fd[2] = { -1, -1 };
static int lldp_handler_calls;
int lldp_network_bind_raw_socket(int ifindex) {
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
@@ -251,28 +48,27 @@ int lldp_network_bind_raw_socket(int ifindex) {
return test_fd[0];
}
static int lldp_handler_calls;
static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
lldp_handler_calls++;
}
static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) {
static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) {
int r;
r = sd_lldp_new(42, "dummy", &mac_addr, lldp);
if (r)
r = sd_lldp_new(lldp, 42);
if (r < 0)
return r;
r = sd_lldp_attach_event(*lldp, e, 0);
if (r)
if (r < 0)
return r;
r = sd_lldp_set_callback(*lldp, cb, cb_data);
if (r)
if (r < 0)
return r;
r = sd_lldp_start(*lldp);
if (r)
if (r < 0)
return r;
return 0;
@@ -282,11 +78,11 @@ static int stop_lldp(sd_lldp *lldp) {
int r;
r = sd_lldp_stop(lldp);
if (r)
if (r < 0)
return r;
r = sd_lldp_detach_event(lldp);
if (r)
if (r < 0)
return r;
sd_lldp_unref(lldp);
@@ -296,13 +92,8 @@ static int stop_lldp(sd_lldp *lldp) {
}
static void test_receive_basic_packet(sd_event *e) {
sd_lldp *lldp;
sd_lldp_packet **packets;
uint8_t type, *data;
uint16_t length, ttl;
int dest_type;
char *str;
uint8_t frame[] = {
static const uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
@@ -319,51 +110,53 @@ static void test_receive_basic_packet(sd_event *e) {
0x00, 0x00 /* End Of LLDPDU */
};
sd_lldp *lldp;
sd_lldp_neighbor **neighbors;
uint8_t type;
const void *data;
uint16_t ttl;
size_t length;
const char *str;
lldp_handler_calls = 0;
assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0);
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 1);
assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0);
assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0);
assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS);
assert_se(length == ETH_ALEN);
assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN));
assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0);
assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0);
assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME);
assert_se(length == 3);
assert_se(strneq((char *) data, "1/3", 3));
assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0);
assert_se(length == 4);
assert_se(strneq(str, "Port", 4));
assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0);
assert_se(streq(str, "Port"));
assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0);
assert_se(length == 3);
assert_se(strneq(str, "SYS", 3));
assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0);
assert_se(streq(str, "SYS"));
assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0);
assert_se(length == 4); /* This is the real length in the TLV packet */
assert_se(strneq(str, "foo", 3));
assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0);
assert_se(streq(str, "foo"));
assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0);
assert_se(ttl == 120);
assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0);
assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE);
sd_lldp_packet_unref(packets[0]);
free(packets);
sd_lldp_neighbor_unref(neighbors[0]);
free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
static void test_receive_incomplete_packet(sd_event *e) {
sd_lldp *lldp;
sd_lldp_packet **packets;
sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -383,18 +176,14 @@ static void test_receive_incomplete_packet(sd_event *e) {
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 0);
assert_se(sd_lldp_get_packets(lldp, &packets) == 0);
assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0);
assert_se(stop_lldp(lldp) == 0);
}
static void test_receive_oui_packet(sd_event *e) {
sd_lldp *lldp;
sd_lldp_packet **packets;
uint32_t id32;
uint16_t id16, len;
uint8_t flags;
char *str;
sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -426,29 +215,30 @@ static void test_receive_oui_packet(sd_event *e) {
assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame));
sd_event_run(e, 0);
assert_se(lldp_handler_calls == 1);
assert_se(sd_lldp_get_packets(lldp, &packets) == 1);
assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0);
assert_se(id16 == 0x1234);
assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0);
assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_CHASSIS_ID) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_PORT_ID) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_TTL) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_END) > 0);
assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0);
assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0);
assert_se(flags == 1);
assert_se(id16 == 0x7788);
assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0);
assert_se(id16 == 0x1234);
assert_se(len == 6);
assert_se(strneq(str, "Vlan51", 6));
assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0);
assert_se(id16 == 0x0102);
assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0);
assert_se(flags == 1);
assert_se(id32 == 0x00140012);
sd_lldp_packet_unref(packets[0]);
free(packets);
sd_lldp_neighbor_unref(neighbors[0]);
free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
@@ -456,7 +246,7 @@ static void test_receive_oui_packet(sd_event *e) {
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
test_parser();
log_set_max_level(LOG_DEBUG);
/* LLDP reception tests */
assert_se(sd_event_new(&e) == 0);

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "hashmap.h"
#include "set.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -16,7 +18,6 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sparse-endian.h"
#include "util.h"

View File

@@ -616,7 +616,7 @@ int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
return 0;
}
int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) {
struct ifinfomsg *ifi;
assert_return(m, -EINVAL);

View File

@@ -774,7 +774,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
return 1;
}
int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) {
int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
int r;
assert_return(rtnl, -EINVAL);

View File

@@ -31,6 +31,7 @@
#include "fs-util.h"
#include "macro.h"
#include "parse-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
@@ -102,16 +103,16 @@ _public_ int sd_network_get_route_domains(char ***ret) {
}
static int network_link_get_string(int ifindex, const char *field, char **ret) {
_cleanup_free_ char *s = NULL, *p = NULL;
char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
_cleanup_free_ char *s = NULL;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(ret, -EINVAL);
if (asprintf(&p, "/run/systemd/netif/links/%i", ifindex) < 0)
return -ENOMEM;
xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
r = parse_env_file(p, NEWLINE, field, &s, NULL);
r = parse_env_file(path, NEWLINE, field, &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@@ -126,17 +127,16 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) {
}
static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
_cleanup_free_ char *p = NULL, *s = NULL;
char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
_cleanup_strv_free_ char **a = NULL;
_cleanup_free_ char *s = NULL;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(ret, -EINVAL);
if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
return -ENOMEM;
r = parse_env_file(p, NEWLINE, key, &s, NULL);
xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
r = parse_env_file(path, NEWLINE, key, &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@@ -187,32 +187,7 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char
return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
}
_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) {
_cleanup_free_ char *s = NULL, *p = NULL;
size_t size;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(lldp, -EINVAL);
if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0)
return -ENOMEM;
r = read_full_file(p, &s, &size);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
return r;
if (size <= 0)
return -ENODATA;
*lldp = s;
s = NULL;
return 0;
}
int sd_network_link_get_timezone(int ifindex, char **ret) {
_public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
return network_link_get_string(ifindex, "TIMEZONE", ret);
}
@@ -232,12 +207,65 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
}
_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret);
static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
_cleanup_strv_free_ char **a = NULL;
_cleanup_free_ int *ifis = NULL;
_cleanup_free_ char *s = NULL;
size_t allocated = 0, c = 0;
const char *x;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(ret, -EINVAL);
xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
r = parse_env_file(path, NEWLINE, key, &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
return r;
if (isempty(s)) {
*ret = NULL;
return 0;
}
x = s;
for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&x, &word, NULL, 0);
if (r < 0)
return r;
if (r == 0)
break;
r = parse_ifindex(word, &ifindex);
if (r < 0)
return r;
if (!GREEDY_REALLOC(ifis, allocated, c + 1))
return -ENOMEM;
ifis[c++] = ifindex;
}
if (!GREEDY_REALLOC(ifis, allocated, c + 1))
return -ENOMEM;
ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/
*ret = ifis;
ifis = NULL;
return c;
}
_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret);
_public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
}
_public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
}
static inline int MONITOR_TO_FD(sd_network_monitor *m) {

View File

@@ -1191,7 +1191,7 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd
return 1;
}
_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) {
_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) {
int r;
assert_return(resolve, -EINVAL);

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "libudev.h"
#include "sd-device.h"

File diff suppressed because it is too large Load Diff

View File

@@ -26,9 +26,11 @@
#include "dhcp-lease-internal.h"
#include "fd-util.h"
#include "fileio.h"
#include "lldp.h"
#include "netlink-util.h"
#include "network-internal.h"
#include "networkd-link.h"
#include "networkd-lldp-tx.h"
#include "networkd-netdev.h"
#include "set.h"
#include "socket-util.h"
@@ -38,7 +40,9 @@
#include "util.h"
#include "virt.h"
bool link_dhcp6_enabled(Link *link) {
static bool link_dhcp6_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
@@ -48,7 +52,9 @@ bool link_dhcp6_enabled(Link *link) {
return link->network->dhcp & ADDRESS_FAMILY_IPV6;
}
bool link_dhcp4_enabled(Link *link) {
static bool link_dhcp4_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
@@ -58,7 +64,9 @@ bool link_dhcp4_enabled(Link *link) {
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
}
bool link_dhcp4_server_enabled(Link *link) {
static bool link_dhcp4_server_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
@@ -68,7 +76,9 @@ bool link_dhcp4_server_enabled(Link *link) {
return link->network->dhcp_server;
}
bool link_ipv4ll_enabled(Link *link) {
static bool link_ipv4ll_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
@@ -78,7 +88,9 @@ bool link_ipv4ll_enabled(Link *link) {
return link->network->link_local & ADDRESS_FAMILY_IPV4;
}
bool link_ipv6ll_enabled(Link *link) {
static bool link_ipv6ll_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
@@ -88,20 +100,42 @@ bool link_ipv6ll_enabled(Link *link) {
return link->network->link_local & ADDRESS_FAMILY_IPV6;
}
bool link_lldp_enabled(Link *link) {
static bool link_lldp_rx_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
if (link->iftype != ARPHRD_ETHER)
return false;
if (!link->network)
return false;
if (link->network->bridge)
return false;
return link->network->lldp;
return link->network->lldp_mode != LLDP_MODE_NO;
}
static bool link_lldp_tx_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
if (link->iftype != ARPHRD_ETHER)
return false;
if (!link->network)
return false;
return link->network->lldp_emit;
}
static bool link_ipv4_forward_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
@@ -115,6 +149,7 @@ static bool link_ipv4_forward_enabled(Link *link) {
}
static bool link_ipv6_forward_enabled(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
return false;
@@ -131,7 +166,9 @@ static bool link_ipv6_forward_enabled(Link *link) {
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
}
bool link_ipv6_accept_ra_enabled(Link *link) {
static bool link_ipv6_accept_ra_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
return false;
@@ -300,6 +337,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
uint16_t type;
const char *ifname;
int r, ifindex;
unsigned short iftype;
assert(manager);
assert(message);
@@ -317,6 +355,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
else if (ifindex <= 0)
return -EINVAL;
r = sd_rtnl_message_link_get_type(message, &iftype);
if (r < 0)
return r;
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
if (r < 0)
return r;
@@ -330,30 +372,24 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
link->state = LINK_STATE_PENDING;
link->rtnl_extended_attrs = true;
link->ifindex = ifindex;
link->iftype = iftype;
link->ifname = strdup(ifname);
if (!link->ifname)
return -ENOMEM;
r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
if (r < 0)
log_link_debug(link, "MAC address not found for new device, continuing without");
log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
r = asprintf(&link->state_file, "/run/systemd/netif/links/%d",
link->ifindex);
if (r < 0)
if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0)
return -ENOMEM;
r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d",
link->ifindex);
if (r < 0)
if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0)
return -ENOMEM;
r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d",
link->ifindex);
if (r < 0)
if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0)
return -ENOMEM;
r = hashmap_ensure_allocated(&manager->links, NULL);
if (r < 0)
return r;
@@ -399,10 +435,11 @@ static void link_free(Link *link) {
sd_dhcp_client_unref(link->dhcp_client);
sd_dhcp_lease_unref(link->dhcp_lease);
link_lldp_tx_stop(link);
free(link->lease_file);
sd_lldp_unref(link->lldp);
free(link->lldp_file);
sd_ipv4ll_unref(link->ipv4ll);
@@ -506,33 +543,28 @@ static int link_stop_clients(Link *link) {
if (link->dhcp_client) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
r = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m");
r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
}
if (link->ipv4ll) {
k = sd_ipv4ll_stop(link->ipv4ll);
if (k < 0)
r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
}
if (link->dhcp6_client) {
k = sd_dhcp6_client_stop(link->dhcp6_client);
if (k < 0)
r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
}
if (link->ndisc_router_discovery) {
k = sd_ndisc_stop(link->ndisc_router_discovery);
if (k < 0)
r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
}
if (link->lldp) {
k = sd_lldp_stop(link->lldp);
if (k < 0)
r = log_link_warning_errno(link, r, "Could not stop LLDP: %m");
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
}
link_lldp_tx_stop(link);
return r;
}
@@ -1211,7 +1243,7 @@ static int link_set_bridge(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
if(link->network->cost != 0) {
if (link->network->cost != 0) {
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
@@ -1230,23 +1262,93 @@ static int link_set_bridge(Link *link) {
return r;
}
static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
static int link_lldp_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
sd_lldp_neighbor **l = NULL;
int n = 0, r, i;
assert(link);
assert(link->lldp_file);
if (!link->lldp) {
(void) unlink(link->lldp_file);
return 0;
}
r = sd_lldp_get_neighbors(link->lldp, &l);
if (r < 0)
goto finish;
if (r == 0) {
(void) unlink(link->lldp_file);
goto finish;
}
n = r;
r = fopen_temporary(link->lldp_file, &f, &temp_path);
if (r < 0)
goto finish;
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);
(void) fwrite(&u, 1, sizeof(u), f);
(void) fwrite(p, 1, sz, f);
}
r = fflush_and_check(f);
if (r < 0)
goto finish;
if (rename(temp_path, link->lldp_file) < 0) {
r = -errno;
goto finish;
}
finish:
if (r < 0) {
(void) unlink(link->lldp_file);
if (temp_path)
(void) unlink(temp_path);
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;
}
static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
Link *link = userdata;
int r;
assert(link);
assert(link->network);
assert(link->manager);
switch (event) {
case SD_LLDP_EVENT_UPDATE_INFO:
r = sd_lldp_save(link->lldp, link->lldp_file);
(void) link_lldp_save(link);
if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) {
/* If we received information about a new neighbor, restart the LLDP "fast" logic */
log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission.");
r = link_lldp_tx_start(link);
if (r < 0)
log_link_warning_errno(link, r, "Could not save LLDP: %m");
break;
default:
break;
log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m");
}
}
@@ -1311,14 +1413,10 @@ static int link_acquire_conf(Link *link) {
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
}
if (link_lldp_enabled(link)) {
assert(link->lldp);
log_link_debug(link, "Starting LLDP");
r = sd_lldp_start(link->lldp);
if (link_lldp_tx_enabled(link)) {
r = link_lldp_tx_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not start LLDP: %m");
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
}
return 0;
@@ -1559,7 +1657,7 @@ static int link_new_bound_by_list(Link *link) {
m = link->manager;
HASHMAP_FOREACH (carrier, m->links, i) {
HASHMAP_FOREACH(carrier, m->links, i) {
if (!carrier->network)
continue;
@@ -1578,7 +1676,7 @@ static int link_new_bound_by_list(Link *link) {
if (list_updated)
link_dirty(link);
HASHMAP_FOREACH (carrier, link->bound_by_links, i) {
HASHMAP_FOREACH(carrier, link->bound_by_links, i) {
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
if (r < 0)
return r;
@@ -2030,6 +2128,27 @@ static int link_drop_foreign_config(Link *link) {
return 0;
}
static int link_update_lldp(Link *link) {
int r;
assert(link);
if (!link->lldp)
return 0;
if (link->flags & IFF_UP) {
r = sd_lldp_start(link->lldp);
if (r > 0)
log_link_debug(link, "Started LLDP.");
} else {
r = sd_lldp_stop(link->lldp);
if (r > 0)
log_link_debug(link, "Stopped LLDP.");
}
return r;
}
static int link_configure(Link *link) {
int r;
@@ -2108,8 +2227,19 @@ static int link_configure(Link *link) {
return r;
}
if (link_lldp_enabled(link)) {
r = sd_lldp_new(link->ifindex, link->ifname, &link->mac, &link->lldp);
if (link_lldp_rx_enabled(link)) {
r = sd_lldp_new(&link->lldp, link->ifindex);
if (r < 0)
return r;
r = sd_lldp_match_capabilities(link->lldp,
link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ?
_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS :
_LLDP_SYSTEM_CAPABILITIES_ALL);
if (r < 0)
return r;
r = sd_lldp_set_filter_address(link->lldp, &link->mac);
if (r < 0)
return r;
@@ -2117,8 +2247,11 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = sd_lldp_set_callback(link->lldp,
lldp_handler, link);
r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
if (r < 0)
return r;
r = link_update_lldp(link);
if (r < 0)
return r;
}
@@ -2562,7 +2695,6 @@ int link_carrier_reset(Link *link) {
return 0;
}
int link_update(Link *link, sd_netlink_message *m) {
struct ether_addr mac;
const char *ifname;
@@ -2668,6 +2800,10 @@ int link_update(Link *link, sd_netlink_message *m) {
if (r < 0)
return r;
r = link_update_lldp(link);
if (r < 0)
return r;
carrier_gained = !had_carrier && link_has_carrier(link);
carrier_lost = had_carrier && !link_has_carrier(link);
@@ -2683,12 +2819,34 @@ int link_update(Link *link, sd_netlink_message *m) {
r = link_carrier_lost(link);
if (r < 0)
return r;
}
return 0;
}
static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
bool space = false;
Iterator i;
Link *link;
assert(f);
assert(prefix);
if (hashmap_isempty(h))
return;
fputs(prefix, f);
HASHMAP_FOREACH(link, h, i) {
if (space)
fputc(' ', f);
fprintf(f, "%i", link->ifindex);
space = true;
}
fputc('\n', f);
}
int link_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -2708,6 +2866,8 @@ int link_save(Link *link) {
return 0;
}
link_lldp_save(link);
admin_state = link_state_to_string(link->state);
assert(admin_state);
@@ -2887,27 +3047,8 @@ int link_save(Link *link) {
fputc('\n', f);
}
if (!hashmap_isempty(link->bound_to_links)) {
Link *carrier;
bool space = false;
fputs("CARRIER_BOUND_TO=", f);
HASHMAP_FOREACH(carrier, link->bound_to_links, i)
fputs_with_space(f, carrier->ifname, NULL, &space);
fputc('\n', f);
}
if (!hashmap_isempty(link->bound_by_links)) {
Link *carrier;
bool space = false;
fputs("CARRIER_BOUND_BY=", f);
HASHMAP_FOREACH(carrier, link->bound_by_links, i)
fputs_with_space(f, carrier->ifname, NULL, &space);
fputc('\n', f);
}
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
if (link->dhcp_lease) {
struct in_addr address;
@@ -2947,19 +3088,6 @@ int link_save(Link *link) {
}
}
if (link->lldp) {
assert(link->network);
r = sd_lldp_save(link->lldp, link->lldp_file);
if (r < 0)
goto fail;
fprintf(f,
"LLDP_FILE=%s\n",
link->lldp_file);
} else
unlink(link->lldp_file);
r = fflush_and_check(f);
if (r < 0)
goto fail;

View File

@@ -65,6 +65,7 @@ struct Link {
int ifindex;
char *ifname;
unsigned short iftype;
char *state_file;
struct ether_addr mac;
struct in6_addr ipv6ll_address;
@@ -111,9 +112,14 @@ struct Link {
sd_dhcp6_client *dhcp6_client;
bool rtnl_extended_attrs;
/* This is about LLDP reception */
sd_lldp *lldp;
char *lldp_file;
/* This is about LLDP transmission */
unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */
sd_event_source *lldp_tx_event_source;
Hashmap *bound_by_links;
Hashmap *bound_to_links;
};
@@ -154,14 +160,6 @@ int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link);
int ndisc_configure(Link *link);
bool link_lldp_enabled(Link *link);
bool link_ipv4ll_enabled(Link *link);
bool link_ipv6ll_enabled(Link *link);
bool link_dhcp4_server_enabled(Link *link);
bool link_dhcp4_enabled(Link *link);
bool link_dhcp6_enabled(Link *link);
bool link_ipv6_accept_ra_enabled(Link *link);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;

View File

@@ -0,0 +1,347 @@
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <endian.h>
#include <inttypes.h>
#include <string.h>
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h"
#include "lldp.h"
#include "networkd-lldp-tx.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "unaligned.h"
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
#define LLDP_TX_FAST_INIT 4U
/* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
#define LLDP_TX_HOLD 4U
/* The jitter range to add, see 9.2.2. */
#define LLDP_JITTER_USEC (400U * USEC_PER_MSEC)
/* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */
#define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
assert(p);
if (id > 127)
return -EBADMSG;
if (sz > 511)
return -ENOBUFS;
(*p)[0] = (id << 1) | !!(sz & 256);
(*p)[1] = sz & 255;
*p = *p + 2;
return 0;
}
static int lldp_make_packet(
const struct ether_addr *hwaddr,
const char *machine_id,
const char *ifname,
uint16_t ttl,
const char *port_description,
const char *hostname,
const char *pretty_hostname,
uint16_t system_capabilities,
uint16_t enabled_capabilities,
void **ret, size_t *sz) {
size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0;
_cleanup_free_ void *packet = NULL;
struct ether_header *h;
uint8_t *p;
size_t l;
int r;
assert(hwaddr);
assert(machine_id);
assert(ifname);
assert(ret);
assert(sz);
machine_id_length = strlen(machine_id);
ifname_length = strlen(ifname);
if (port_description)
port_description_length = strlen(port_description);
if (hostname)
hostname_length = strlen(hostname);
if (pretty_hostname)
pretty_hostname_length = strlen(pretty_hostname);
l = sizeof(struct ether_header) +
/* Chassis ID */
2 + 1 + machine_id_length +
/* Port ID */
2 + 1 + ifname_length +
/* TTL */
2 + 2 +
/* System Capabilities */
2 + 4 +
/* End */
2;
/* Port Description */
if (port_description)
l += 2 + port_description_length;
/* System Name */
if (hostname)
l += 2 + hostname_length;
/* System Description */
if (pretty_hostname)
l += 2 + pretty_hostname_length;
packet = malloc(l);
if (!packet)
return -ENOMEM;
h = (struct ether_header*) packet;
h->ether_type = htobe16(ETHERTYPE_LLDP);
memcpy(h->ether_dhost, &(struct ether_addr) { LLDP_MULTICAST_ADDR }, ETH_ALEN);
memcpy(h->ether_shost, hwaddr, ETH_ALEN);
p = (uint8_t*) packet + sizeof(struct ether_header);
r = lldp_write_tlv_header(&p, LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length);
if (r < 0)
return r;
*(p++) = LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED;
p = mempcpy(p, machine_id, machine_id_length);
r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_ID, 1 + ifname_length);
if (r < 0)
return r;
*(p++) = LLDP_PORT_SUBTYPE_INTERFACE_NAME;
p = mempcpy(p, ifname, ifname_length);
r = lldp_write_tlv_header(&p, LLDP_TYPE_TTL, 2);
if (r < 0)
return r;
unaligned_write_be16(p, ttl);
p += 2;
if (port_description) {
r = lldp_write_tlv_header(&p, LLDP_TYPE_PORT_DESCRIPTION, port_description_length);
if (r < 0)
return r;
p = mempcpy(p, port_description, port_description_length);
}
if (hostname) {
r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_NAME, hostname_length);
if (r < 0)
return r;
p = mempcpy(p, hostname, hostname_length);
}
if (pretty_hostname) {
r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length);
if (r < 0)
return r;
p = mempcpy(p, pretty_hostname, pretty_hostname_length);
}
r = lldp_write_tlv_header(&p, LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
if (r < 0)
return r;
unaligned_write_be16(p, system_capabilities);
p += 2;
unaligned_write_be16(p, enabled_capabilities);
p += 2;
r = lldp_write_tlv_header(&p, LLDP_TYPE_END, 0);
if (r < 0)
return r;
assert(p == (uint8_t*) packet + l);
*ret = packet;
*sz = l;
packet = NULL;
return 0;
}
static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) {
union sockaddr_union sa = {
.ll.sll_family = AF_PACKET,
.ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
.ll.sll_ifindex = ifindex,
.ll.sll_halen = ETH_ALEN,
.ll.sll_addr = LLDP_MULTICAST_ADDR,
};
_cleanup_close_ int fd = -1;
ssize_t l;
assert(ifindex > 0);
assert(packet || packet_size <= 0);
fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
if (fd < 0)
return -errno;
l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll));
if (l < 0)
return -errno;
if ((size_t) l != packet_size)
return -EIO;
return 0;
}
static int link_send_lldp(Link *link) {
char machine_id_string[SD_ID128_STRING_MAX];
_cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL;
_cleanup_free_ void *packet = NULL;
size_t packet_size = 0;
sd_id128_t machine_id;
uint16_t caps;
usec_t ttl;
int r;
r = sd_id128_get_machine(&machine_id);
if (r < 0)
return r;
(void) gethostname_strict(&hostname);
(void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL);
ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC);
if (ttl > (usec_t) UINT16_MAX)
ttl = (usec_t) UINT16_MAX;
caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ?
LLDP_SYSTEM_CAPABILITIES_ROUTER :
LLDP_SYSTEM_CAPABILITIES_STATION;
r = lldp_make_packet(&link->mac,
sd_id128_to_string(machine_id, machine_id_string),
link->ifname,
(uint16_t) ttl,
link->network ? link->network->description : NULL,
hostname,
pretty_hostname,
LLDP_SYSTEM_CAPABILITIES_STATION|LLDP_SYSTEM_CAPABILITIES_BRIDGE|LLDP_SYSTEM_CAPABILITIES_ROUTER,
caps,
&packet, &packet_size);
if (r < 0)
return r;
return lldp_send_packet(link->ifindex, packet, packet_size);
}
static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
Link *link = userdata;
usec_t current, delay, next;
int r;
assert(s);
assert(userdata);
log_link_debug(link, "Sending LLDP packet...");
r = link_send_lldp(link);
if (r < 0)
log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m");
if (link->lldp_tx_fast > 0)
link->lldp_tx_fast--;
assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), &current) >= 0);
delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC;
next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC);
r = sd_event_source_set_time(s, next);
if (r < 0)
return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m");
r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
if (r < 0)
return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m");
return 0;
}
int link_lldp_tx_start(Link *link) {
usec_t next;
int r;
assert(link);
/* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */
link->lldp_tx_fast = LLDP_TX_FAST_INIT;
next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
(usec_t) random_u64() % LLDP_JITTER_USEC);
if (link->lldp_tx_event_source) {
usec_t old;
/* Lower the timeout, maybe */
r = sd_event_source_get_time(link->lldp_tx_event_source, &old);
if (r < 0)
return r;
if (old <= next)
return 0;
return sd_event_source_set_time(link->lldp_tx_event_source, next);
} else {
r = sd_event_add_time(
link->manager->event,
&link->lldp_tx_event_source,
clock_boottime_or_monotonic(),
next,
0,
on_lldp_timer,
link);
if (r < 0)
return r;
(void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx");
}
return 0;
}
void link_lldp_tx_stop(Link *link) {
assert(link);
link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source);
}

View File

@@ -0,0 +1,25 @@
#pragma once
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "networkd-link.h"
int link_lldp_tx_start(Link *link);
void link_lldp_tx_stop(Link *link);

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct Bridge Bridge;
#include "networkd-netdev.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct Dummy Dummy;
#include "networkd-netdev.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct IPVlan IPVlan;
#include "missing.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct MacVlan MacVlan;
#include "networkd-netdev.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct Tunnel Tunnel;
#include "networkd-netdev.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct TunTap TunTap;
#include "networkd-netdev.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct Veth Veth;
#include "networkd-netdev.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct VLan VLan;
#include "networkd-netdev.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
typedef struct VxLan VxLan;
#include "in-addr-util.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "list.h"
typedef struct NetDev NetDev;

View File

@@ -40,7 +40,8 @@ Network.DHCPServer, config_parse_bool,
Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local)
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp)
Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode)
Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit)
Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
Network.Domains, config_parse_domains, 0, 0

View File

@@ -119,6 +119,8 @@ static int network_load_one(Manager *manager, const char *filename) {
network->allow_port_to_be_root = true;
network->unicast_flood = true;
network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
network->llmnr = RESOLVE_SUPPORT_YES;
network->mdns = RESOLVE_SUPPORT_NO;
network->dnssec_mode = _DNSSEC_MODE_INVALID;
@@ -1017,3 +1019,13 @@ static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
[LLDP_MODE_NO] = "no",
[LLDP_MODE_YES] = "yes",
[LLDP_MODE_ROUTERS_ONLY] = "routers-only",
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);

View File

@@ -58,6 +58,14 @@ typedef enum DHCPUseDomains {
_DHCP_USE_DOMAINS_INVALID = -1,
} DHCPUseDomains;
typedef enum LLDPMode {
LLDP_MODE_NO = 0,
LLDP_MODE_YES = 1,
LLDP_MODE_ROUTERS_ONLY = 2,
_LLDP_MODE_MAX,
_LLDP_MODE_INVALID = -1,
} LLDPMode;
struct Network {
Manager *manager;
@@ -137,7 +145,8 @@ struct Network {
struct ether_addr *mac;
unsigned mtu;
bool lldp;
LLDPMode lldp_mode; /* LLDP reception */
bool lldp_emit; /* LLDP transmission */
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);
@@ -181,6 +190,7 @@ int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigne
int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_lldp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -197,3 +207,6 @@ IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;
const char* lldp_mode_to_string(LLDPMode m) _const_;
LLDPMode lldp_mode_from_string(const char *s) _pure_;

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "sd-event.h"
#include "sd-netlink.h"
#include "sd-network.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <arpa/inet.h>
#include "sd-bus.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "macro.h"
/* DNS record types, taken from

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <endian.h>
#include "sd-id128.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "install.h"
int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret);

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
int parse_sleep_config(const char *verb, char ***modes, char ***states);
int can_sleep(const char *verb);

View File

@@ -84,9 +84,9 @@ enum {
typedef struct sd_dhcp_client sd_dhcp_client;
typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event,
typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event,
void *userdata);
int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_callback_t cb,
void *userdata);
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option);
@@ -113,7 +113,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
int sd_dhcp_client_new(sd_dhcp_client **ret);
int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority);
int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority);
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);

View File

@@ -37,7 +37,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex);
sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server);
sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server);
int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority);
int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int64_t priority);
int sd_dhcp_server_detach_event(sd_dhcp_server *client);
sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client);

View File

@@ -76,10 +76,10 @@ enum {
typedef struct sd_dhcp6_client sd_dhcp6_client;
typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event,
typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event,
void *userdata);
int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
sd_dhcp6_client_cb_t cb, void *userdata);
sd_dhcp6_client_callback_t cb, void *userdata);
int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address);
@@ -97,8 +97,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
int sd_dhcp6_client_stop(sd_dhcp6_client *client);
int sd_dhcp6_client_start(sd_dhcp6_client *client);
int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
int priority);
int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority);
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);

View File

@@ -37,12 +37,12 @@ enum {
};
typedef struct sd_ipv4acd sd_ipv4acd;
typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata);
typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata);
int sd_ipv4acd_detach_event(sd_ipv4acd *ll);
int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority);
int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority);
int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address);
int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata);
int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);

View File

@@ -36,12 +36,12 @@ enum {
};
typedef struct sd_ipv4ll sd_ipv4ll;
typedef void (*sd_ipv4ll_cb_t)(sd_ipv4ll *ll, int event, void *userdata);
typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata);
int sd_ipv4ll_detach_event(sd_ipv4ll *ll);
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority);
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority);
int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address);

View File

@@ -30,57 +30,69 @@
_SD_BEGIN_DECLARATIONS;
enum {
SD_LLDP_EVENT_UPDATE_INFO = 0,
};
enum {
SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE,
SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE,
SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE,
};
typedef struct sd_lldp sd_lldp;
typedef struct sd_lldp_packet sd_lldp_packet;
typedef struct sd_lldp_neighbor sd_lldp_neighbor;
typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
typedef enum sd_lldp_event {
SD_LLDP_EVENT_ADDED = 'a',
SD_LLDP_EVENT_REMOVED = 'r',
SD_LLDP_EVENT_UPDATED = 'u',
SD_LLDP_EVENT_REFRESHED = 'f',
} sd_lldp_event;
int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret);
typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);
int sd_lldp_new(sd_lldp **ret, int ifindex);
sd_lldp* sd_lldp_unref(sd_lldp *lldp);
int sd_lldp_start(sd_lldp *lldp);
int sd_lldp_stop(sd_lldp *lldp);
int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority);
int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority);
int sd_lldp_detach_event(sd_lldp *lldp);
int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata);
int sd_lldp_save(sd_lldp *lldp, const char *file);
int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata);
int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length);
int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl);
int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length);
int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data);
int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length);
/* Controls how much and what to store in the neighbors database */
int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n);
int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask);
int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *address);
/* IEEE 802.1 organizationally specific TLVs */
int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id);
int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id);
int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length);
int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id);
int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id);
int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors);
sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv);
sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv);
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);
int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
/* Access to LLDP frame metadata */
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_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
/* 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);
int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret);
int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret);
int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
/* Low-level, iterative TLV access. This is for evertyhing else, it iteratively goes through all available TLVs
* (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */
int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n);
int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n);
int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type);
int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type);
int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype);
int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype);
int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref);
_SD_END_DECLARATIONS;

View File

@@ -52,7 +52,7 @@ int sd_ndisc_set_callback(sd_ndisc *nd,
int sd_ndisc_set_index(sd_ndisc *nd, int interface_index);
int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority);
int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
int sd_ndisc_detach_event(sd_ndisc *nd);
sd_event *sd_ndisc_get_event(sd_ndisc *nd);

View File

@@ -64,7 +64,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout);
int sd_netlink_add_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
int sd_netlink_remove_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int priority);
int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority);
int sd_netlink_detach_event(sd_netlink *nl);
int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data);
@@ -131,7 +131,7 @@ int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type);
int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family);
int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex);
int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type);
int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type);
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);

View File

@@ -99,11 +99,11 @@ int sd_network_link_get_network_file(int ifindex, char **filename);
/* Get DNS entries for a given link. These are string representations of
* IP addresses */
int sd_network_link_get_dns(int ifindex, char ***addr);
int sd_network_link_get_dns(int ifindex, char ***ret);
/* Get NTP entries for a given link. These are domain names or string
* representations of IP addresses */
int sd_network_link_get_ntp(int ifindex, char ***addr);
int sd_network_link_get_ntp(int ifindex, char ***ret);
/* Indicates whether or not LLMNR should be enabled for the link
* Possible levels of support: yes, no, resolve
@@ -133,19 +133,17 @@ int sd_network_link_get_dnssec(int ifindex, char **dnssec);
*/
int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta);
int sd_network_link_get_lldp(int ifindex, char **lldp);
/* Get the search DNS domain names for a given link. */
int sd_network_link_get_search_domains(int ifindex, char ***domains);
/* Get the route DNS domain names for a given link. */
int sd_network_link_get_route_domains(int ifindex, char ***domains);
/* Get the CARRIERS to which current link is bound to. */
int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers);
/* Get the carrier interface indexes to which current link is bound to. */
int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes);
/* Get the CARRIERS that are bound to current link. */
int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers);
int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes);
/* Get the timezone that was learnt on a specific link. */
int sd_network_link_get_timezone(int ifindex, char **timezone);

View File

@@ -79,7 +79,7 @@ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec);
int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid);
int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int priority);
int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int64_t priority);
int sd_resolve_detach_event(sd_resolve *resolve);
sd_event *sd_resolve_get_event(sd_resolve *resolve);

View File

@@ -1,3 +1,5 @@
#pragma once
/*
* Copyright (C) 2010 - Maxim Levitsky
*
@@ -17,8 +19,6 @@
* Boston, MA 02110-1301 USA
*/
#pragma once
#include <mtd/mtd-user.h>
#include "macro.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include <macro.h>
/* we can't use DUPLEX_ prefix, as it

View File

@@ -1,3 +1,5 @@
#pragma once
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#pragma once
#include "libudev.h"
#include "condition.h"

View File

@@ -1,3 +1,5 @@
#pragma once
/*
* scsi.h
*
@@ -10,8 +12,6 @@
* Free Software Foundation version 2 of the License.
*/
#pragma once
#include <scsi/scsi.h>
struct scsi_ioctl_command {

View File

@@ -1,3 +1,5 @@
#pragma once
/*
* Copyright (C) IBM Corp. 2003
*
@@ -15,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define MAX_PATH_LEN 512
/*

View File

@@ -1,3 +1,5 @@
#pragma once
/*
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 2003-2010 Kay Sievers <kay@vrfy.org>
@@ -16,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <sys/param.h>
#include <sys/types.h>

View File

@@ -1,3 +1,5 @@
#pragma once
/*
* Copyright (C) 2014 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
*
@@ -15,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "udev.h"
struct udev_device *find_device(struct udev *udev,