summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2016-05-06 21:27:36 +0200
committerLennart Poettering <lennart@poettering.net>2016-05-09 15:45:31 +0200
commit7272b25e163d1c7395ff0da1397511c7946c0873 (patch)
tree71e0ed754449c7131589b50e340ce2be7f867599 /src/network
parentd31645adefb3462d168b44bb950f92654c395021 (diff)
networkd: reworkd LLDP emission to allow control of propagation level
This allows selecting the propagation level of emitted LLDP packets (specifically: the destination MAC address of the packets). This is useful because it allows generating LLDP packets that optionally cross certain types of bridges. See 802.11ab-2009, Table 7-1 for details.
Diffstat (limited to 'src/network')
-rw-r--r--src/network/networkd-link.c16
-rw-r--r--src/network/networkd-link.h2
-rw-r--r--src/network/networkd-lldp-tx.c102
-rw-r--r--src/network/networkd-lldp-tx.h14
-rw-r--r--src/network/networkd-network-gperf.gperf2
-rw-r--r--src/network/networkd-network.h3
6 files changed, 108 insertions, 31 deletions
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index c646af1f1a..4e3f62cf51 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -131,7 +131,7 @@ static bool link_lldp_rx_enabled(Link *link) {
return link->network->lldp_mode != LLDP_MODE_NO;
}
-static bool link_lldp_tx_enabled(Link *link) {
+static bool link_lldp_emit_enabled(Link *link) {
assert(link);
if (link->flags & IFF_LOOPBACK)
@@ -143,7 +143,7 @@ static bool link_lldp_tx_enabled(Link *link) {
if (!link->network)
return false;
- return link->network->lldp_emit;
+ return link->network->lldp_emit != LLDP_EMIT_NO;
}
static bool link_ipv4_forward_enabled(Link *link) {
@@ -491,7 +491,7 @@ 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);
+ link_lldp_emit_stop(link);
free(link->lease_file);
@@ -618,7 +618,7 @@ static int link_stop_clients(Link *link) {
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
}
- link_lldp_tx_stop(link);
+ link_lldp_emit_stop(link);
return r;
}
@@ -1411,12 +1411,12 @@ static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n
(void) link_lldp_save(link);
- if (link_lldp_tx_enabled(link) && event == SD_LLDP_EVENT_ADDED) {
+ if (link_lldp_emit_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);
+ r = link_lldp_emit_start(link);
if (r < 0)
log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m");
}
@@ -1501,8 +1501,8 @@ static int link_acquire_conf(Link *link) {
return r;
}
- if (link_lldp_tx_enabled(link)) {
- r = link_lldp_tx_start(link);
+ if (link_lldp_emit_enabled(link)) {
+ r = link_lldp_emit_start(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
}
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 86139be557..14c4a02c7e 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -121,7 +121,7 @@ typedef struct Link {
/* 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;
+ sd_event_source *lldp_emit_event_source;
Hashmap *bound_by_links;
Hashmap *bound_to_links;
diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c
index 03b694c3f1..3aa768388b 100644
--- a/src/network/networkd-lldp-tx.c
+++ b/src/network/networkd-lldp-tx.c
@@ -25,16 +25,14 @@
#include "fd-util.h"
#include "fileio.h"
#include "hostname-util.h"
+#include "networkd-lldp-tx.h"
+#include "networkd.h"
+#include "parse-util.h"
#include "random-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "unaligned.h"
-#include "networkd.h"
-#include "networkd-lldp-tx.h"
-
-#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
-
/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
#define LLDP_TX_FAST_INIT 4U
@@ -50,6 +48,12 @@
/* 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 const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = {
+ [LLDP_EMIT_NEAREST_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }},
+ [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }},
+ [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }},
+};
+
static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
assert(p);
@@ -66,6 +70,7 @@ static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
}
static int lldp_make_packet(
+ LLDPEmit mode,
const struct ether_addr *hwaddr,
const char *machine_id,
const char *ifname,
@@ -84,6 +89,8 @@ static int lldp_make_packet(
size_t l;
int r;
+ assert(mode > LLDP_EMIT_NO);
+ assert(mode < _LLDP_EMIT_MAX);
assert(hwaddr);
assert(machine_id);
assert(ifname);
@@ -132,7 +139,7 @@ static int lldp_make_packet(
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_dhost, lldp_multicast_addr + mode, ETH_ALEN);
memcpy(h->ether_shost, hwaddr, ETH_ALEN);
p = (uint8_t*) packet + sizeof(struct ether_header);
@@ -197,22 +204,28 @@ static int lldp_make_packet(
return 0;
}
-static int lldp_send_packet(int ifindex, const void *packet, size_t packet_size) {
+static int lldp_send_packet(
+ int ifindex,
+ const struct ether_addr *address,
+ 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(address);
assert(packet || packet_size <= 0);
+ memcpy(sa.ll.sll_addr, address, ETH_ALEN);
+
fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
if (fd < 0)
return -errno;
@@ -237,6 +250,13 @@ static int link_send_lldp(Link *link) {
usec_t ttl;
int r;
+ assert(link);
+
+ if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO)
+ return 0;
+
+ assert(link->network->lldp_emit < _LLDP_EMIT_MAX);
+
r = sd_id128_get_machine(&machine_id);
if (r < 0)
return r;
@@ -251,7 +271,8 @@ static int link_send_lldp(Link *link) {
SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
SD_LLDP_SYSTEM_CAPABILITIES_STATION;
- r = lldp_make_packet(&link->mac,
+ r = lldp_make_packet(link->network->lldp_emit,
+ &link->mac,
sd_id128_to_string(machine_id, machine_id_string),
link->ifname,
(uint16_t) ttl,
@@ -264,7 +285,7 @@ static int link_send_lldp(Link *link) {
if (r < 0)
return r;
- return lldp_send_packet(link->ifindex, packet, packet_size);
+ return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size);
}
static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
@@ -300,12 +321,17 @@ static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
return 0;
}
-int link_lldp_tx_start(Link *link) {
+int link_lldp_emit_start(Link *link) {
usec_t next;
int r;
assert(link);
+ if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
+ link_lldp_emit_stop(link);
+ return 0;
+ }
+
/* 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;
@@ -313,22 +339,22 @@ int link_lldp_tx_start(Link *link) {
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) {
+ if (link->lldp_emit_event_source) {
usec_t old;
/* Lower the timeout, maybe */
- r = sd_event_source_get_time(link->lldp_tx_event_source, &old);
+ r = sd_event_source_get_time(link->lldp_emit_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);
+ return sd_event_source_set_time(link->lldp_emit_event_source, next);
} else {
r = sd_event_add_time(
link->manager->event,
- &link->lldp_tx_event_source,
+ &link->lldp_emit_event_source,
clock_boottime_or_monotonic(),
next,
0,
@@ -337,14 +363,54 @@ int link_lldp_tx_start(Link *link) {
if (r < 0)
return r;
- (void) sd_event_source_set_description(link->lldp_tx_event_source, "lldp-tx");
+ (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx");
}
return 0;
}
-void link_lldp_tx_stop(Link *link) {
+void link_lldp_emit_stop(Link *link) {
assert(link);
- link->lldp_tx_event_source = sd_event_source_unref(link->lldp_tx_event_source);
+ link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source);
+}
+
+int config_parse_lldp_emit(
+ 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) {
+
+ LLDPEmit *emit = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue))
+ *emit = LLDP_EMIT_NO;
+ else if (streq(rvalue, "nearest-bridge"))
+ *emit = LLDP_EMIT_NEAREST_BRIDGE;
+ else if (streq(rvalue, "non-tpmr-bridge"))
+ *emit = LLDP_EMIT_NON_TPMR_BRIDGE;
+ else if (streq(rvalue, "customer-bridge"))
+ *emit = LLDP_EMIT_CUSTOMER_BRIDGE;
+ else {
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO;
+ }
+
+ return 0;
}
diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h
index 8c7f403005..4680c9d950 100644
--- a/src/network/networkd-lldp-tx.h
+++ b/src/network/networkd-lldp-tx.h
@@ -21,5 +21,15 @@
#include "networkd-link.h"
-int link_lldp_tx_start(Link *link);
-void link_lldp_tx_stop(Link *link);
+typedef enum LLDPEmit {
+ LLDP_EMIT_NO,
+ LLDP_EMIT_NEAREST_BRIDGE,
+ LLDP_EMIT_NON_TPMR_BRIDGE,
+ LLDP_EMIT_CUSTOMER_BRIDGE,
+ _LLDP_EMIT_MAX,
+} LLDPEmit;
+
+int link_lldp_emit_start(Link *link);
+void link_lldp_emit_stop(Link *link);
+
+int config_parse_lldp_emit(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);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index a9a541559e..4425ee4e2f 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -42,7 +42,7 @@ Network.LinkLocalAddressing, config_parse_address_family_boolean,
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode)
-Network.EmitLLDP, config_parse_bool, 0, offsetof(Network, lldp_emit)
+Network.EmitLLDP, config_parse_lldp_emit, 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
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index ff2414efdd..4cd0fa4ab8 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -29,6 +29,7 @@
#include "networkd-address.h"
#include "networkd-fdb.h"
+#include "networkd-lldp-tx.h"
#include "networkd-netdev.h"
#include "networkd-route.h"
#include "networkd-util.h"
@@ -161,7 +162,7 @@ struct Network {
DUID duid;
LLDPMode lldp_mode; /* LLDP reception */
- bool lldp_emit; /* LLDP transmission */
+ LLDPEmit lldp_emit; /* LLDP transmission */
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);