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