]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-lldp-tx.c
network: ignore requested ipv6 fdb entry when ipv6 is disabled by sysctl
[thirdparty/systemd.git] / src / network / networkd-lldp-tx.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8e1ad1ea
LP
2
3#include <endian.h>
4#include <inttypes.h>
0b200472 5#include <net/if.h>
8e1ad1ea
LP
6#include <string.h>
7
634f0f98 8#include "alloc-util.h"
686d13b9 9#include "env-file.h"
8e1ad1ea 10#include "fd-util.h"
8e1ad1ea 11#include "hostname-util.h"
ef118d00 12#include "missing_network.h"
0b200472 13#include "networkd-link.h"
7272b25e 14#include "networkd-lldp-tx.h"
23f53b99 15#include "networkd-manager.h"
7272b25e 16#include "parse-util.h"
8e1ad1ea
LP
17#include "random-util.h"
18#include "socket-util.h"
19#include "string-util.h"
20#include "unaligned.h"
21
22/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
23#define LLDP_TX_FAST_INIT 4U
24
25/* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
26#define LLDP_TX_HOLD 4U
27
28/* The jitter range to add, see 9.2.2. */
29#define LLDP_JITTER_USEC (400U * USEC_PER_MSEC)
30
31/* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */
32#define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
33
34/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
35#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
36
7272b25e
LP
37static const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = {
38 [LLDP_EMIT_NEAREST_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }},
39 [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }},
40 [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }},
41};
42
0b200472
YW
43bool link_lldp_emit_enabled(Link *link) {
44 assert(link);
45
46 if (link->flags & IFF_LOOPBACK)
47 return false;
48
49 if (link->iftype != ARPHRD_ETHER)
50 return false;
51
52 if (!link->network)
53 return false;
54
55 return link->network->lldp_emit != LLDP_EMIT_NO;
56}
57
8e1ad1ea
LP
58static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
59 assert(p);
60
61 if (id > 127)
62 return -EBADMSG;
63 if (sz > 511)
64 return -ENOBUFS;
65
66 (*p)[0] = (id << 1) | !!(sz & 256);
67 (*p)[1] = sz & 255;
68
69 *p = *p + 2;
70 return 0;
71}
72
73static int lldp_make_packet(
7272b25e 74 LLDPEmit mode,
8e1ad1ea
LP
75 const struct ether_addr *hwaddr,
76 const char *machine_id,
77 const char *ifname,
78 uint16_t ttl,
79 const char *port_description,
80 const char *hostname,
81 const char *pretty_hostname,
82 uint16_t system_capabilities,
83 uint16_t enabled_capabilities,
84 void **ret, size_t *sz) {
85
86 size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0;
87 _cleanup_free_ void *packet = NULL;
88 struct ether_header *h;
89 uint8_t *p;
90 size_t l;
91 int r;
92
7272b25e
LP
93 assert(mode > LLDP_EMIT_NO);
94 assert(mode < _LLDP_EMIT_MAX);
8e1ad1ea
LP
95 assert(hwaddr);
96 assert(machine_id);
97 assert(ifname);
98 assert(ret);
99 assert(sz);
100
101 machine_id_length = strlen(machine_id);
102 ifname_length = strlen(ifname);
103
104 if (port_description)
105 port_description_length = strlen(port_description);
106
107 if (hostname)
108 hostname_length = strlen(hostname);
109
110 if (pretty_hostname)
111 pretty_hostname_length = strlen(pretty_hostname);
112
113 l = sizeof(struct ether_header) +
114 /* Chassis ID */
115 2 + 1 + machine_id_length +
116 /* Port ID */
117 2 + 1 + ifname_length +
118 /* TTL */
119 2 + 2 +
120 /* System Capabilities */
121 2 + 4 +
122 /* End */
123 2;
124
125 /* Port Description */
126 if (port_description)
127 l += 2 + port_description_length;
128
129 /* System Name */
130 if (hostname)
131 l += 2 + hostname_length;
132
133 /* System Description */
134 if (pretty_hostname)
135 l += 2 + pretty_hostname_length;
136
137 packet = malloc(l);
138 if (!packet)
139 return -ENOMEM;
140
141 h = (struct ether_header*) packet;
142 h->ether_type = htobe16(ETHERTYPE_LLDP);
7272b25e 143 memcpy(h->ether_dhost, lldp_multicast_addr + mode, ETH_ALEN);
8e1ad1ea
LP
144 memcpy(h->ether_shost, hwaddr, ETH_ALEN);
145
146 p = (uint8_t*) packet + sizeof(struct ether_header);
147
6afa6767 148 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length);
8e1ad1ea
LP
149 if (r < 0)
150 return r;
6afa6767 151 *(p++) = SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED;
8e1ad1ea
LP
152 p = mempcpy(p, machine_id, machine_id_length);
153
6afa6767 154 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_ID, 1 + ifname_length);
8e1ad1ea
LP
155 if (r < 0)
156 return r;
6afa6767 157 *(p++) = SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME;
8e1ad1ea
LP
158 p = mempcpy(p, ifname, ifname_length);
159
6afa6767 160 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_TTL, 2);
8e1ad1ea
LP
161 if (r < 0)
162 return r;
163 unaligned_write_be16(p, ttl);
164 p += 2;
165
166 if (port_description) {
6afa6767 167 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_DESCRIPTION, port_description_length);
8e1ad1ea
LP
168 if (r < 0)
169 return r;
170 p = mempcpy(p, port_description, port_description_length);
171 }
172
173 if (hostname) {
6afa6767 174 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_NAME, hostname_length);
8e1ad1ea
LP
175 if (r < 0)
176 return r;
177 p = mempcpy(p, hostname, hostname_length);
178 }
179
180 if (pretty_hostname) {
6afa6767 181 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length);
8e1ad1ea
LP
182 if (r < 0)
183 return r;
184 p = mempcpy(p, pretty_hostname, pretty_hostname_length);
185 }
186
6afa6767 187 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
8e1ad1ea
LP
188 if (r < 0)
189 return r;
190 unaligned_write_be16(p, system_capabilities);
191 p += 2;
192 unaligned_write_be16(p, enabled_capabilities);
193 p += 2;
194
6afa6767 195 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_END, 0);
8e1ad1ea
LP
196 if (r < 0)
197 return r;
198
199 assert(p == (uint8_t*) packet + l);
200
1cc6c93a 201 *ret = TAKE_PTR(packet);
8e1ad1ea
LP
202 *sz = l;
203
8e1ad1ea
LP
204 return 0;
205}
206
7272b25e
LP
207static int lldp_send_packet(
208 int ifindex,
209 const struct ether_addr *address,
210 const void *packet,
211 size_t packet_size) {
8e1ad1ea
LP
212
213 union sockaddr_union sa = {
214 .ll.sll_family = AF_PACKET,
215 .ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
216 .ll.sll_ifindex = ifindex,
217 .ll.sll_halen = ETH_ALEN,
8e1ad1ea
LP
218 };
219
220 _cleanup_close_ int fd = -1;
221 ssize_t l;
222
223 assert(ifindex > 0);
7272b25e 224 assert(address);
8e1ad1ea
LP
225 assert(packet || packet_size <= 0);
226
7272b25e
LP
227 memcpy(sa.ll.sll_addr, address, ETH_ALEN);
228
8e1ad1ea
LP
229 fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
230 if (fd < 0)
231 return -errno;
232
233 l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll));
234 if (l < 0)
235 return -errno;
236
237 if ((size_t) l != packet_size)
238 return -EIO;
239
240 return 0;
241}
242
243static int link_send_lldp(Link *link) {
244 char machine_id_string[SD_ID128_STRING_MAX];
245 _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL;
246 _cleanup_free_ void *packet = NULL;
247 size_t packet_size = 0;
248 sd_id128_t machine_id;
249 uint16_t caps;
250 usec_t ttl;
251 int r;
252
7272b25e
LP
253 assert(link);
254
255 if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO)
256 return 0;
257
258 assert(link->network->lldp_emit < _LLDP_EMIT_MAX);
259
8e1ad1ea
LP
260 r = sd_id128_get_machine(&machine_id);
261 if (r < 0)
262 return r;
263
264 (void) gethostname_strict(&hostname);
13df9c39 265 (void) parse_env_file(NULL, "/etc/machine-info", "PRETTY_HOSTNAME", &pretty_hostname);
8e1ad1ea 266
c8cf4dc1 267 assert_cc(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1 <= (UINT16_MAX - 1) * USEC_PER_SEC);
8e1ad1ea 268 ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC);
8e1ad1ea
LP
269
270 caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ?
6afa6767
BG
271 SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
272 SD_LLDP_SYSTEM_CAPABILITIES_STATION;
8e1ad1ea 273
7272b25e
LP
274 r = lldp_make_packet(link->network->lldp_emit,
275 &link->mac,
8e1ad1ea
LP
276 sd_id128_to_string(machine_id, machine_id_string),
277 link->ifname,
278 (uint16_t) ttl,
279 link->network ? link->network->description : NULL,
280 hostname,
281 pretty_hostname,
6afa6767 282 SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER,
8e1ad1ea
LP
283 caps,
284 &packet, &packet_size);
285 if (r < 0)
286 return r;
287
7272b25e 288 return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size);
8e1ad1ea
LP
289}
290
291static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
292 Link *link = userdata;
293 usec_t current, delay, next;
294 int r;
295
296 assert(s);
297 assert(userdata);
298
299 log_link_debug(link, "Sending LLDP packet...");
300
301 r = link_send_lldp(link);
302 if (r < 0)
303 log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m");
304
305 if (link->lldp_tx_fast > 0)
306 link->lldp_tx_fast--;
307
308 assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), &current) >= 0);
309
310 delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC;
311 next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC);
312
313 r = sd_event_source_set_time(s, next);
314 if (r < 0)
315 return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m");
316
317 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
318 if (r < 0)
319 return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m");
320
321 return 0;
322}
323
7272b25e 324int link_lldp_emit_start(Link *link) {
8e1ad1ea
LP
325 usec_t next;
326 int r;
327
328 assert(link);
329
7272b25e
LP
330 if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
331 link_lldp_emit_stop(link);
332 return 0;
333 }
334
8e1ad1ea
LP
335 /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */
336
337 link->lldp_tx_fast = LLDP_TX_FAST_INIT;
338
339 next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
340 (usec_t) random_u64() % LLDP_JITTER_USEC);
341
7272b25e 342 if (link->lldp_emit_event_source) {
8e1ad1ea
LP
343 usec_t old;
344
345 /* Lower the timeout, maybe */
7272b25e 346 r = sd_event_source_get_time(link->lldp_emit_event_source, &old);
8e1ad1ea
LP
347 if (r < 0)
348 return r;
349
350 if (old <= next)
351 return 0;
352
7272b25e 353 return sd_event_source_set_time(link->lldp_emit_event_source, next);
8e1ad1ea
LP
354 } else {
355 r = sd_event_add_time(
356 link->manager->event,
7272b25e 357 &link->lldp_emit_event_source,
8e1ad1ea
LP
358 clock_boottime_or_monotonic(),
359 next,
360 0,
361 on_lldp_timer,
362 link);
363 if (r < 0)
364 return r;
365
7272b25e 366 (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx");
8e1ad1ea
LP
367 }
368
369 return 0;
370}
371
7272b25e 372void link_lldp_emit_stop(Link *link) {
8e1ad1ea
LP
373 assert(link);
374
7272b25e
LP
375 link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source);
376}
377
378int config_parse_lldp_emit(
379 const char *unit,
380 const char *filename,
381 unsigned line,
382 const char *section,
383 unsigned section_line,
384 const char *lvalue,
385 int ltype,
386 const char *rvalue,
387 void *data,
388 void *userdata) {
389
390 LLDPEmit *emit = data;
391 int r;
392
393 assert(filename);
394 assert(lvalue);
395 assert(rvalue);
396
397 if (isempty(rvalue))
398 *emit = LLDP_EMIT_NO;
399 else if (streq(rvalue, "nearest-bridge"))
400 *emit = LLDP_EMIT_NEAREST_BRIDGE;
401 else if (streq(rvalue, "non-tpmr-bridge"))
402 *emit = LLDP_EMIT_NON_TPMR_BRIDGE;
403 else if (streq(rvalue, "customer-bridge"))
404 *emit = LLDP_EMIT_CUSTOMER_BRIDGE;
405 else {
406 r = parse_boolean(rvalue);
407 if (r < 0) {
408 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue);
409 return 0;
410 }
411
412 *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO;
413 }
414
415 return 0;
8e1ad1ea 416}