]> git.proxmox.com Git - systemd.git/blob - src/network/networkd-lldp-rx.c
New upstream version 249~rc1
[systemd.git] / src / network / networkd-lldp-rx.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if.h>
4 #include <net/if_arp.h>
5 #include <unistd.h>
6
7 #include "fd-util.h"
8 #include "fileio.h"
9 #include "fs-util.h"
10 #include "networkd-link.h"
11 #include "networkd-lldp-rx.h"
12 #include "networkd-lldp-tx.h"
13 #include "networkd-manager.h"
14 #include "networkd-network.h"
15 #include "string-table.h"
16 #include "string-util.h"
17 #include "strv.h"
18 #include "tmpfile-util.h"
19
20 DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
21
22 static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
23 [LLDP_MODE_NO] = "no",
24 [LLDP_MODE_YES] = "yes",
25 [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
26 };
27
28 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
29
30 static bool link_lldp_rx_enabled(Link *link) {
31 assert(link);
32
33 if (link->flags & IFF_LOOPBACK)
34 return false;
35
36 if (link->iftype != ARPHRD_ETHER)
37 return false;
38
39 if (!link->network)
40 return false;
41
42 /* LLDP should be handled on bridge and bond slaves as those have a direct connection to their peers,
43 * not on the bridge/bond master. Linux doesn't even (by default) forward lldp packets to the bridge
44 * master. */
45 if (link->kind && STR_IN_SET(link->kind, "bridge", "bond"))
46 return false;
47
48 return link->network->lldp_mode != LLDP_MODE_NO;
49 }
50
51 static void lldp_handler(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n, void *userdata) {
52 Link *link = userdata;
53 int r;
54
55 assert(link);
56
57 (void) link_lldp_save(link);
58
59 if (link_lldp_emit_enabled(link) && event == SD_LLDP_EVENT_ADDED) {
60 /* If we received information about a new neighbor, restart the LLDP "fast" logic */
61
62 log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission.");
63
64 r = link_lldp_emit_start(link);
65 if (r < 0)
66 log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m");
67 }
68 }
69
70 int link_lldp_rx_configure(Link *link) {
71 int r;
72
73 if (!link_lldp_rx_enabled(link))
74 return 0;
75
76 if (link->lldp)
77 return -EBUSY;
78
79 r = sd_lldp_new(&link->lldp);
80 if (r < 0)
81 return r;
82
83 r = sd_lldp_attach_event(link->lldp, link->manager->event, 0);
84 if (r < 0)
85 return r;
86
87 r = sd_lldp_set_ifindex(link->lldp, link->ifindex);
88 if (r < 0)
89 return r;
90
91 r = sd_lldp_match_capabilities(link->lldp,
92 link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ?
93 SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS :
94 SD_LLDP_SYSTEM_CAPABILITIES_ALL);
95 if (r < 0)
96 return r;
97
98 r = sd_lldp_set_filter_address(link->lldp, &link->hw_addr.ether);
99 if (r < 0)
100 return r;
101
102 r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
103 if (r < 0)
104 return r;
105
106 r = link_update_lldp(link);
107 if (r < 0)
108 return r;
109
110 return 0;
111 }
112
113 int link_update_lldp(Link *link) {
114 int r;
115
116 assert(link);
117
118 if (!link->lldp)
119 return 0;
120
121 if (link->flags & IFF_UP) {
122 r = sd_lldp_start(link->lldp);
123 if (r < 0)
124 return log_link_warning_errno(link, r, "Failed to start LLDP: %m");
125 if (r > 0)
126 log_link_debug(link, "Started LLDP.");
127 } else {
128 r = sd_lldp_stop(link->lldp);
129 if (r < 0)
130 return log_link_warning_errno(link, r, "Failed to stop LLDP: %m");
131 if (r > 0)
132 log_link_debug(link, "Stopped LLDP.");
133 }
134
135 return r;
136 }
137
138 int link_lldp_save(Link *link) {
139 _cleanup_(unlink_and_freep) char *temp_path = NULL;
140 _cleanup_fclose_ FILE *f = NULL;
141 sd_lldp_neighbor **l = NULL;
142 int n = 0, r, i;
143
144 assert(link);
145 assert(link->lldp_file);
146
147 if (!link->lldp) {
148 (void) unlink(link->lldp_file);
149 return 0;
150 }
151
152 r = sd_lldp_get_neighbors(link->lldp, &l);
153 if (r < 0)
154 return r;
155 if (r == 0) {
156 (void) unlink(link->lldp_file);
157 return 0;
158 }
159
160 n = r;
161
162 r = fopen_temporary(link->lldp_file, &f, &temp_path);
163 if (r < 0)
164 goto finish;
165
166 (void) fchmod(fileno(f), 0644);
167
168 for (i = 0; i < n; i++) {
169 const void *p;
170 le64_t u;
171 size_t sz;
172
173 r = sd_lldp_neighbor_get_raw(l[i], &p, &sz);
174 if (r < 0)
175 goto finish;
176
177 u = htole64(sz);
178 (void) fwrite(&u, 1, sizeof(u), f);
179 (void) fwrite(p, 1, sz, f);
180 }
181
182 r = fflush_and_check(f);
183 if (r < 0)
184 goto finish;
185
186 r = conservative_rename(temp_path, link->lldp_file);
187 if (r < 0)
188 goto finish;
189
190 finish:
191 if (r < 0)
192 log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
193
194 if (l) {
195 for (i = 0; i < n; i++)
196 sd_lldp_neighbor_unref(l[i]);
197 free(l);
198 }
199
200 return r;
201 }