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