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