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