Branch data 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 [ - + - + : 12 : 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 [ + + + + : 52 : 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 : 28 : int link_update_lldp(Link *link) {
105 : : int r;
106 : :
107 [ - + ]: 28 : assert(link);
108 : :
109 [ + - ]: 28 : if (!link->lldp)
110 : 28 : 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 : : }
|