]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/link.c
networkd: Store any flags
[people/ms/network.git] / src / networkd / link.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <net/if.h>
22 #include <stddef.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <systemd/sd-netlink.h>
27
28 #include "daemon.h"
29 #include "link.h"
30 #include "links.h"
31 #include "logging.h"
32 #include "string.h"
33
34 struct nw_link {
35 nw_daemon* daemon;
36 int nrefs;
37
38 // Interface Index
39 int ifindex;
40
41 // Interface Name
42 char ifname[IF_NAMESIZE];
43
44 // MTU
45 uint32_t mtu;
46 uint32_t min_mtu;
47 uint32_t max_mtu;
48
49 // Flags
50 unsigned int flags;
51 };
52
53 int nw_link_create(nw_link** link, nw_daemon* daemon, int ifindex) {
54 // Allocate a new object
55 nw_link* l = calloc(1, sizeof(*l));
56 if (!l)
57 return 1;
58
59 // Store a reference to the daemon
60 l->daemon = nw_daemon_ref(daemon);
61
62 // Initialize the reference counter
63 l->nrefs = 1;
64
65 // Store the ifindex
66 l->ifindex = ifindex;
67
68 DEBUG("New link allocated (ifindex = %d)\n", l->ifindex);
69
70 *link = l;
71
72 return 0;
73 }
74
75 static void nw_link_free(nw_link* link) {
76 DEBUG("Freeing link (ifindex = %d)\n", link->ifindex);
77
78 if (link->daemon)
79 nw_daemon_unref(link->daemon);
80 }
81
82 nw_link* nw_link_ref(nw_link* link) {
83 link->nrefs++;
84
85 return link;
86 }
87
88 nw_link* nw_link_unref(nw_link* link) {
89 if (--link->nrefs > 0)
90 return link;
91
92 nw_link_free(link);
93 return NULL;
94 }
95
96 int nw_link_ifindex(nw_link* link) {
97 return link->ifindex;
98 }
99
100 static int nw_link_update_ifname(nw_link* link, sd_netlink_message* message) {
101 const char* ifname = NULL;
102 int r;
103
104 r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
105 if (r < 0) {
106 ERROR("Could not read link name for link %d: %m\n", link->ifindex);
107 return 1;
108 }
109
110 // Do nothing if the name is already set
111 if (strcmp(link->ifname, ifname) == 0)
112 return 0;
113
114 // Otherwise update the name
115 r = nw_string_set(link->ifname, ifname);
116 if (r) {
117 ERROR("Could not set link name: %m\n");
118 return 1;
119 }
120
121 DEBUG("Link %d has been renamed to '%s'\n", link->ifindex, link->ifname);
122
123 return 0;
124 }
125
126 static int nw_link_update_mtu(nw_link* link, sd_netlink_message* message) {
127 uint32_t mtu = 0;
128 uint32_t min_mtu = 0;
129 uint32_t max_mtu = 0;
130 int r;
131
132 // Read the MTU
133 r = sd_netlink_message_read_u32(message, IFLA_MTU, &mtu);
134 if (r < 0) {
135 ERROR("Could not read MTU for link %d: %m\n", link->ifindex);
136 return r;
137 }
138
139 // Read the minimum MTU
140 r = sd_netlink_message_read_u32(message, IFLA_MIN_MTU, &min_mtu);
141 if (r < 0) {
142 ERROR("Could not read the minimum MTU for link %d: %m\n", link->ifindex);
143 return r;
144 }
145
146 // Read the maximum MTU
147 r = sd_netlink_message_read_u32(message, IFLA_MAX_MTU, &max_mtu);
148 if (r < 0) {
149 ERROR("Could not read the maximum MTU for link %d: %m\n", link->ifindex);
150 return r;
151 }
152
153 // Set the maximum MTU to infinity
154 if (!max_mtu)
155 max_mtu = UINT32_MAX;
156
157 // Store min/max MTU
158 link->min_mtu = min_mtu;
159 link->max_mtu = max_mtu;
160
161 // End here, if the MTU has not been changed
162 if (link->mtu == mtu)
163 return 0;
164
165 DEBUG("Link %d: MTU has changed to %" PRIu32 " (min: %" PRIu32 ", max: %" PRIu32 ")\n",
166 link->ifindex, link->mtu, link->min_mtu, link->max_mtu);
167
168 // Store MTU
169 link->mtu = mtu;
170
171 return 0;
172 }
173
174 static int nw_link_update_flags(nw_link* link, sd_netlink_message* message) {
175 unsigned int flags = 0;
176 int r;
177
178 // Fetch flags
179 r = sd_rtnl_message_link_get_flags(message, &flags);
180 if (r < 0) {
181 return DEBUG("Could not read link flags: %m\n");
182 return 1;
183 }
184
185 // End here if there have been no changes
186 if (link->flags == flags)
187 return 0;
188
189 // XXX We should log any changes here
190
191 // Store the new flags
192 link->flags = flags;
193
194 return 0;
195 }
196
197 /*
198 This function is called whenever anything changes, so that we can
199 update our internal link object.
200 */
201 static int nw_link_update(nw_link* link, sd_netlink_message* message) {
202 int r;
203
204 // Update the interface name
205 r = nw_link_update_ifname(link, message);
206 if (r)
207 return r;
208
209 // Update the MTU
210 r = nw_link_update_mtu(link, message);
211 if (r)
212 return r;
213
214 // Update flags
215 r = nw_link_update_flags(link, message);
216 if (r)
217 return r;
218
219 return 0;
220 }
221
222 int nw_link_process(sd_netlink* rtnl, sd_netlink_message* message, void* data) {
223 nw_links* links = NULL;
224 nw_link* link = NULL;
225 const char* ifname = NULL;
226 int ifindex;
227 uint16_t type;
228 int r;
229
230 nw_daemon* daemon = (nw_daemon*)data;
231
232 // Fetch links
233 links = nw_daemon_links(daemon);
234 if (!links) {
235 r = 1;
236 goto ERROR;
237 }
238
239 // Check if this message could be received
240 if (sd_netlink_message_is_error(message)) {
241 r = sd_netlink_message_get_errno(message);
242 if (r < 0)
243 ERROR("Could not receive link message: %m\n");
244
245 goto IGNORE;
246 }
247
248 // Fetch the message type
249 r = sd_netlink_message_get_type(message, &type);
250 if (r < 0) {
251 ERROR("Could not fetch message type: %m\n");
252 goto IGNORE;
253 }
254
255 // Check type
256 switch (type) {
257 case RTM_NEWLINK:
258 case RTM_DELLINK:
259 break;
260
261 default:
262 ERROR("Received an unexpected message (type %u)\n", type);
263 goto IGNORE;
264 }
265
266 // Fetch the interface index
267 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
268 if (r < 0) {
269 ERROR("Could not fetch ifindex: %m\n");
270 goto IGNORE;
271 }
272
273 // Check interface index
274 if (ifindex <= 0) {
275 ERROR("Received an invalid ifindex\n");
276 goto IGNORE;
277 }
278
279 // Fetch the interface name
280 r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
281 if (r < 0) {
282 ERROR("Received a netlink message without interface name: %m\n");
283 goto IGNORE;
284 }
285
286 // Try finding an existing link
287 link = nw_daemon_get_link_by_ifindex(daemon, ifindex);
288
289 switch (type) {
290 case RTM_NEWLINK:
291 // If the link doesn't exist, create it
292 if (!link) {
293 r = nw_link_create(&link, daemon, ifindex);
294 if (r) {
295 ERROR("Could not create link: %m\n");
296 goto ERROR;
297 }
298
299 // Add it to the list
300 r = nw_links_add_link(links, link);
301 if (r)
302 goto ERROR;
303 }
304
305 // Import any data from the netlink message
306 r = nw_link_update(link, message);
307 if (r)
308 goto ERROR;
309
310 break;
311
312 case RTM_DELLINK:
313 if (link)
314 nw_links_drop_link(links, link);
315
316 break;
317 }
318
319 IGNORE:
320 r = 0;
321
322 ERROR:
323 if (links)
324 nw_links_unref(links);
325 if (link)
326 nw_link_unref(link);
327
328 return r;
329 }