]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/zone.c
9f5b7f8cba45bfbb6afbe2bbfe1a9aa7e39216e9
[people/ms/network.git] / src / networkd / zone.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 <limits.h>
22 #include <linux/if_link.h>
23 #include <stdlib.h>
24
25 #include <systemd/sd-bus.h>
26
27 #include "config.h"
28 #include "daemon.h"
29 #include "link.h"
30 #include "logging.h"
31 #include "stats-collector.h"
32 #include "string.h"
33 #include "zone.h"
34
35 struct nw_zone {
36 nw_daemon* daemon;
37 int nrefs;
38
39 // Link
40 nw_link* link;
41
42 char name[NETWORK_ZONE_NAME_MAX_LENGTH];
43
44 // Configuration
45 nw_config *config;
46 };
47
48 #define nw_zone_path(zone, path, format, ...) \
49 __nw_zone_path(zone, path, sizeof(path), format, __VA_ARGS__)
50
51 static int __nw_zone_path(nw_zone* zone, char* p, const size_t length,
52 const char* format, ...) {
53 char prefix[NAME_MAX];
54 char suffix[NAME_MAX];
55 va_list args;
56 int r;
57
58 // Format the prefix
59 r = nw_string_format(prefix, "%s/zones/%s", CONFIG_DIR, zone->name);
60 if (r)
61 return r;
62
63 // Format the suffix
64 va_start(args, format);
65 r = nw_string_vformat(suffix, format, args);
66 va_end(args);
67 if (r)
68 return r;
69
70 // Join the two parts together
71 return __nw_path_join(p, length, prefix, suffix);
72 }
73
74 static void nw_zone_free(nw_zone* zone) {
75 if (zone->link)
76 nw_link_unref(zone->link);
77 if (zone->config)
78 nw_config_unref(zone->config);
79 if (zone->daemon)
80 nw_daemon_unref(zone->daemon);
81
82 free(zone);
83 }
84
85 static int nw_zone_set_link(nw_zone* zone, nw_link* link) {
86 // Do nothing if the same link is being re-assigned
87 if (zone->link == link)
88 return 0;
89
90 // Dereference the former link if set
91 if (zone->link)
92 nw_link_unref(zone->link);
93
94 // Store the new link
95 if (link) {
96 zone->link = nw_link_ref(link);
97
98 DEBUG("Zone %s: Assigned link %d\n", zone->name, nw_link_ifindex(zone->link));
99
100 // Or clear the pointer if no link has been provided
101 } else {
102 zone->link = NULL;
103
104 DEBUG("Zone %s: Removed link\n", zone->name);
105 }
106
107 return 0;
108 }
109
110 static int nw_zone_setup(nw_zone* zone) {
111 nw_link* link = NULL;
112 char path[PATH_MAX];
113 int r;
114
115 // Find the link
116 link = nw_daemon_get_link_by_name(zone->daemon, zone->name);
117 if (link) {
118 r = nw_zone_set_link(zone, link);
119 if (r)
120 goto ERROR;
121 }
122
123 // Compose the path to the main configuration file
124 r = nw_zone_path(zone, path, "%s", "settings");
125 if (r)
126 goto ERROR;
127
128 // Initialize the configuration
129 r = nw_config_create(&zone->config, path);
130 if (r)
131 goto ERROR;
132
133 ERROR:
134 if (link)
135 nw_link_unref(link);
136
137 return r;
138 }
139
140 int nw_zone_create(nw_zone** zone, nw_daemon* daemon, const char* name) {
141 int r;
142
143 // Allocate a new object
144 nw_zone* z = calloc(1, sizeof(*z));
145 if (!z)
146 return 1;
147
148 // Store a reference to the daemon
149 z->daemon = nw_daemon_ref(daemon);
150
151 // Initialize reference counter
152 z->nrefs = 1;
153
154 // Store the name
155 r = nw_string_set(z->name, name);
156 if (r)
157 goto ERROR;
158
159 // Setup the zone
160 r = nw_zone_setup(z);
161 if (r)
162 goto ERROR;
163
164 *zone = z;
165 return 0;
166
167 ERROR:
168 nw_zone_free(z);
169 return r;
170 }
171
172 nw_zone* nw_zone_ref(nw_zone* zone) {
173 zone->nrefs++;
174
175 return zone;
176 }
177
178 nw_zone* nw_zone_unref(nw_zone* zone) {
179 if (--zone->nrefs > 0)
180 return zone;
181
182 nw_zone_free(zone);
183 return NULL;
184 }
185
186 int __nw_zone_drop_port(nw_daemon* daemon, nw_zone* zone, void* data) {
187 nw_port* dropped_port = (nw_port*)data;
188
189 // XXX TODO
190 (void)dropped_port;
191
192 return 0;
193 }
194
195 int nw_zone_save(nw_zone* zone) {
196 int r;
197
198 r = nw_config_write(zone->config);
199 if (r)
200 return r;
201
202 return 0;
203 }
204
205 const char* nw_zone_name(nw_zone* zone) {
206 return zone->name;
207 }
208
209 char* nw_zone_bus_path(nw_zone* zone) {
210 char* p = NULL;
211 int r;
212
213 // Encode the bus path
214 r = sd_bus_path_encode("/org/ipfire/network1/zone", zone->name, &p);
215 if (r < 0)
216 return NULL;
217
218 return p;
219 }
220
221 int __nw_zone_set_link(nw_daemon* daemon, nw_zone* zone, void* data) {
222 nw_link* link = (nw_link*)data;
223
224 // Fetch the link name
225 const char* ifname = nw_link_ifname(link);
226 if (!ifname) {
227 ERROR("Link does not have a name set\n");
228 return 1;
229 }
230
231 // Set link if the name matches
232 if (strcmp(zone->name, ifname) == 0)
233 return nw_zone_set_link(zone, link);
234
235 // If we have the link set but the name did not match, we will remove it
236 else if (zone->link == link)
237 return nw_zone_set_link(zone, NULL);
238
239 return 0;
240 }
241
242 int __nw_zone_drop_link(nw_daemon* daemon, nw_zone* zone, void* data) {
243 nw_link* link = (nw_link*)data;
244
245 // Drop the link if it matches
246 if (zone->link == link)
247 return nw_zone_set_link(zone, NULL);
248
249 return 0;
250 }
251
252 int nw_zone_reconfigure(nw_zone* zone) {
253 return 0; // XXX TODO
254 }
255
256 // Carrier
257
258 int nw_zone_has_carrier(nw_zone* zone) {
259 if (!zone->link)
260 return 0;
261
262 return nw_link_has_carrier(zone->link);
263 }
264
265 /*
266 MTU
267 */
268 unsigned int nw_zone_mtu(nw_zone* zone) {
269 return nw_config_get_int(zone->config, "MTU", NETWORK_ZONE_DEFAULT_MTU);
270 }
271
272 int nw_zone_set_mtu(nw_zone* zone, unsigned int mtu) {
273 DEBUG("Change MTU of %s to %u\n", zone->name, mtu);
274
275 return nw_config_set_int(zone->config, "MTU", mtu);
276 }
277
278 /*
279 Stats
280 */
281
282 const struct rtnl_link_stats64* nw_zone_get_stats64(nw_zone* zone) {
283 if (!zone->link)
284 return NULL;
285
286 return nw_link_get_stats64(zone->link);
287 }
288
289 int __nw_zone_update_stats(nw_daemon* daemon, nw_zone* zone, void* data) {
290 nw_link* link = (nw_link*)data;
291
292 // Emit stats if link matches
293 if (zone->link == link)
294 return nw_stats_collector_emit_zone_stats(daemon, zone);
295
296 return 0;
297 }
298
299 int nw_zone_update_stats(nw_zone* zone) {
300 if (zone->link)
301 return nw_link_update_stats(zone->link);
302
303 return 0;
304 }