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