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