]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-lldp-tx.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-lldp-tx.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2016 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <endian.h>
22 #include <inttypes.h>
23 #include <string.h>
24
25 #include "alloc-util.h"
26 #include "fd-util.h"
27 #include "fileio.h"
28 #include "hostname-util.h"
29 #include "networkd-lldp-tx.h"
30 #include "networkd-manager.h"
31 #include "parse-util.h"
32 #include "random-util.h"
33 #include "socket-util.h"
34 #include "string-util.h"
35 #include "unaligned.h"
36
37 /* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
38 #define LLDP_TX_FAST_INIT 4U
39
40 /* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
41 #define LLDP_TX_HOLD 4U
42
43 /* The jitter range to add, see 9.2.2. */
44 #define LLDP_JITTER_USEC (400U * USEC_PER_MSEC)
45
46 /* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */
47 #define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
48
49 /* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
50 #define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
51
52 static const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = {
53 [LLDP_EMIT_NEAREST_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }},
54 [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }},
55 [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }},
56 };
57
58 static 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
73 static int lldp_make_packet(
74 LLDPEmit mode,
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
93 assert(mode > LLDP_EMIT_NO);
94 assert(mode < _LLDP_EMIT_MAX);
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);
143 memcpy(h->ether_dhost, lldp_multicast_addr + mode, ETH_ALEN);
144 memcpy(h->ether_shost, hwaddr, ETH_ALEN);
145
146 p = (uint8_t*) packet + sizeof(struct ether_header);
147
148 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length);
149 if (r < 0)
150 return r;
151 *(p++) = SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED;
152 p = mempcpy(p, machine_id, machine_id_length);
153
154 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_ID, 1 + ifname_length);
155 if (r < 0)
156 return r;
157 *(p++) = SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME;
158 p = mempcpy(p, ifname, ifname_length);
159
160 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_TTL, 2);
161 if (r < 0)
162 return r;
163 unaligned_write_be16(p, ttl);
164 p += 2;
165
166 if (port_description) {
167 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_DESCRIPTION, port_description_length);
168 if (r < 0)
169 return r;
170 p = mempcpy(p, port_description, port_description_length);
171 }
172
173 if (hostname) {
174 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_NAME, hostname_length);
175 if (r < 0)
176 return r;
177 p = mempcpy(p, hostname, hostname_length);
178 }
179
180 if (pretty_hostname) {
181 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length);
182 if (r < 0)
183 return r;
184 p = mempcpy(p, pretty_hostname, pretty_hostname_length);
185 }
186
187 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
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
195 r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_END, 0);
196 if (r < 0)
197 return r;
198
199 assert(p == (uint8_t*) packet + l);
200
201 *ret = packet;
202 *sz = l;
203
204 packet = NULL;
205 return 0;
206 }
207
208 static int lldp_send_packet(
209 int ifindex,
210 const struct ether_addr *address,
211 const void *packet,
212 size_t packet_size) {
213
214 union sockaddr_union sa = {
215 .ll.sll_family = AF_PACKET,
216 .ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
217 .ll.sll_ifindex = ifindex,
218 .ll.sll_halen = ETH_ALEN,
219 };
220
221 _cleanup_close_ int fd = -1;
222 ssize_t l;
223
224 assert(ifindex > 0);
225 assert(address);
226 assert(packet || packet_size <= 0);
227
228 memcpy(sa.ll.sll_addr, address, ETH_ALEN);
229
230 fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
231 if (fd < 0)
232 return -errno;
233
234 l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll));
235 if (l < 0)
236 return -errno;
237
238 if ((size_t) l != packet_size)
239 return -EIO;
240
241 return 0;
242 }
243
244 static int link_send_lldp(Link *link) {
245 char machine_id_string[SD_ID128_STRING_MAX];
246 _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL;
247 _cleanup_free_ void *packet = NULL;
248 size_t packet_size = 0;
249 sd_id128_t machine_id;
250 uint16_t caps;
251 usec_t ttl;
252 int r;
253
254 assert(link);
255
256 if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO)
257 return 0;
258
259 assert(link->network->lldp_emit < _LLDP_EMIT_MAX);
260
261 r = sd_id128_get_machine(&machine_id);
262 if (r < 0)
263 return r;
264
265 (void) gethostname_strict(&hostname);
266 (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL);
267
268 assert_cc(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1 <= (UINT16_MAX - 1) * USEC_PER_SEC);
269 ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC);
270
271 caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ?
272 SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
273 SD_LLDP_SYSTEM_CAPABILITIES_STATION;
274
275 r = lldp_make_packet(link->network->lldp_emit,
276 &link->mac,
277 sd_id128_to_string(machine_id, machine_id_string),
278 link->ifname,
279 (uint16_t) ttl,
280 link->network ? link->network->description : NULL,
281 hostname,
282 pretty_hostname,
283 SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER,
284 caps,
285 &packet, &packet_size);
286 if (r < 0)
287 return r;
288
289 return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size);
290 }
291
292 static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
293 Link *link = userdata;
294 usec_t current, delay, next;
295 int r;
296
297 assert(s);
298 assert(userdata);
299
300 log_link_debug(link, "Sending LLDP packet...");
301
302 r = link_send_lldp(link);
303 if (r < 0)
304 log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m");
305
306 if (link->lldp_tx_fast > 0)
307 link->lldp_tx_fast--;
308
309 assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), &current) >= 0);
310
311 delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC;
312 next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC);
313
314 r = sd_event_source_set_time(s, next);
315 if (r < 0)
316 return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m");
317
318 r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
319 if (r < 0)
320 return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m");
321
322 return 0;
323 }
324
325 int link_lldp_emit_start(Link *link) {
326 usec_t next;
327 int r;
328
329 assert(link);
330
331 if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
332 link_lldp_emit_stop(link);
333 return 0;
334 }
335
336 /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */
337
338 link->lldp_tx_fast = LLDP_TX_FAST_INIT;
339
340 next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
341 (usec_t) random_u64() % LLDP_JITTER_USEC);
342
343 if (link->lldp_emit_event_source) {
344 usec_t old;
345
346 /* Lower the timeout, maybe */
347 r = sd_event_source_get_time(link->lldp_emit_event_source, &old);
348 if (r < 0)
349 return r;
350
351 if (old <= next)
352 return 0;
353
354 return sd_event_source_set_time(link->lldp_emit_event_source, next);
355 } else {
356 r = sd_event_add_time(
357 link->manager->event,
358 &link->lldp_emit_event_source,
359 clock_boottime_or_monotonic(),
360 next,
361 0,
362 on_lldp_timer,
363 link);
364 if (r < 0)
365 return r;
366
367 (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx");
368 }
369
370 return 0;
371 }
372
373 void link_lldp_emit_stop(Link *link) {
374 assert(link);
375
376 link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source);
377 }
378
379 int config_parse_lldp_emit(
380 const char *unit,
381 const char *filename,
382 unsigned line,
383 const char *section,
384 unsigned section_line,
385 const char *lvalue,
386 int ltype,
387 const char *rvalue,
388 void *data,
389 void *userdata) {
390
391 LLDPEmit *emit = data;
392 int r;
393
394 assert(filename);
395 assert(lvalue);
396 assert(rvalue);
397
398 if (isempty(rvalue))
399 *emit = LLDP_EMIT_NO;
400 else if (streq(rvalue, "nearest-bridge"))
401 *emit = LLDP_EMIT_NEAREST_BRIDGE;
402 else if (streq(rvalue, "non-tpmr-bridge"))
403 *emit = LLDP_EMIT_NON_TPMR_BRIDGE;
404 else if (streq(rvalue, "customer-bridge"))
405 *emit = LLDP_EMIT_CUSTOMER_BRIDGE;
406 else {
407 r = parse_boolean(rvalue);
408 if (r < 0) {
409 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue);
410 return 0;
411 }
412
413 *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO;
414 }
415
416 return 0;
417 }