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