]>
git.ipfire.org Git - people/ms/network.git/blob - src/networkd/port.c
1 /*#############################################################################
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
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. #
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. #
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/>. #
19 #############################################################################*/
26 #include <systemd/sd-bus.h>
33 #include "stats-collector.h"
43 char name
[IF_NAMESIZE
];
53 static const struct nw_port_type_map
{
56 } nw_port_type_map
[] = {
57 { NW_PORT_DUMMY
, "dummy" },
58 { NW_PORT_UNKNOWN
, NULL
},
61 static nw_port_type_t
nw_port_type_from_string(const char* s
) {
62 const struct nw_port_type_map
* map
= NULL
;
64 for (map
= nw_port_type_map
; *map
->name
; map
++) {
65 if (strcmp(map
->name
, s
) == 0)
69 return NW_PORT_UNKNOWN
;
72 static void nw_port_free(nw_port
* port
) {
74 nw_link_unref(port
->link
);
76 nw_config_unref(port
->config
);
78 nw_daemon_unref(port
->daemon
);
83 static int nw_port_setup_address(nw_port
* port
) {
86 // Read ADDRESS from configuration
87 const char* s
= nw_config_get(port
->config
, "ADDRESS");
89 ERROR("Port %s: Address isn't set\n", port
->name
);
94 r
= nw_address_from_string(&port
->address
, s
);
96 ERROR("Port %s: Could not parse address: %m\n", port
->name
);
100 // Check if this address is usable
101 r
= nw_address_is_multicast(&port
->address
);
103 DEBUG("Port %s: Multicast bit is set on Ethernet address\n", port
->name
);
110 // Generate a random Ethernet address
111 r
= nw_address_generate(&port
->address
);
113 ERROR("Could not generate a random Ethernet address: %m\n");
120 static int nw_port_setup_common(nw_port
* port
) {
124 r
= nw_port_setup_address(port
);
131 static int nw_port_set_link(nw_port
* port
, nw_link
* link
) {
132 // Do nothing if the same link is being re-assigned
133 if (port
->link
== link
)
136 // Dereference the former link if set
138 nw_link_unref(port
->link
);
140 // Store the new link
142 port
->link
= nw_link_ref(link
);
144 DEBUG("Port %s: Assigned link %d\n", port
->name
, nw_link_ifindex(port
->link
));
146 // Or clear the pointer if no link has been provided
150 DEBUG("Port %s: Removed link\n", port
->name
);
156 static int nw_port_setup(nw_port
* port
) {
157 nw_link
* link
= NULL
;
162 link
= nw_daemon_get_link_by_name(port
->daemon
, port
->name
);
164 r
= nw_port_set_link(port
, link
);
169 // Compose the path to the main configuration file
170 r
= nw_path_join(path
, PORT_CONFIG_DIR
, port
->name
);
174 // Initialize the configuration
175 r
= nw_config_create(&port
->config
, path
);
179 // Perform some common initialization
180 r
= nw_port_setup_common(port
);
184 // Call any custom initialization
185 switch (port
->type
) {
186 // These do not need any special initialization
188 case NW_PORT_UNKNOWN
:
199 int nw_port_create(nw_port
** port
, nw_daemon
* daemon
, nw_port_type_t type
, const char* name
) {
202 // Allocate a new object
203 nw_port
* p
= calloc(1, sizeof(*p
));
207 // Store a reference to the daemon
208 p
->daemon
= nw_daemon_ref(daemon
);
210 // Initialize reference counter
217 r
= nw_string_set(p
->name
, name
);
222 r
= nw_port_setup(p
);
234 int nw_port_create_from_config(nw_port
** port
, nw_daemon
* daemon
,
235 const char* name
, const char* path
) {
236 nw_config
* config
= NULL
;
239 // Initialize the configuration
240 r
= nw_config_create(&config
, path
);
245 const char* type
= nw_config_get(config
, "TYPE");
247 ERROR("Port configuration %s has no TYPE\n", path
);
253 r
= nw_port_create(port
, daemon
, nw_port_type_from_string(type
), name
);
259 nw_config_unref(config
);
264 nw_port
* nw_port_ref(nw_port
* port
) {
270 nw_port
* nw_port_unref(nw_port
* port
) {
271 if (--port
->nrefs
> 0)
278 int nw_port_save(nw_port
* port
) {
281 r
= nw_config_write(port
->config
);
288 const char* nw_port_name(nw_port
* port
) {
292 char* nw_port_bus_path(nw_port
* port
) {
296 // Encode the bus path
297 r
= sd_bus_path_encode("/org/ipfire/network1/port", port
->name
, &p
);
304 int __nw_port_set_link(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
305 nw_link
* link
= (nw_link
*)data
;
307 // Fetch the link name
308 const char* ifname
= nw_link_ifname(link
);
310 ERROR("Link does not have a name set\n");
314 // Set link if the name matches
315 if (strcmp(port
->name
, ifname
) == 0)
316 return nw_port_set_link(port
, link
);
318 // If we have the link set but the name did not match, we will remove it
319 else if (port
->link
== link
)
320 return nw_port_set_link(port
, NULL
);
325 int __nw_port_drop_link(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
326 nw_link
* link
= (nw_link
*)data
;
328 // Drop the link if it matches
329 if (port
->link
== link
)
330 return nw_port_set_link(port
, NULL
);
335 const nw_address_t
* nw_port_get_address(nw_port
* port
) {
336 return &port
->address
;
339 static int nw_port_is_disabled(nw_port
* port
) {
340 return nw_config_get_bool(port
->config
, "DISABLED");
343 static int nw_port_create_link(nw_port
* port
) {
344 return 0; // XXX TODO
347 int nw_port_reconfigure(nw_port
* port
) {
350 // If the port is disabled, we will try to destroy it
351 if (nw_port_is_disabled(port
)) {
353 r
= nw_link_destroy(port
->link
);
361 // If there is no link, we will try to create it
363 r
= nw_port_create_link(port
);
373 int nw_port_has_carrier(nw_port
* port
) {
377 return nw_link_has_carrier(port
->link
);
384 const struct rtnl_link_stats64
* nw_port_get_stats64(nw_port
* port
) {
388 return nw_link_get_stats64(port
->link
);
391 int __nw_port_update_stats(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
392 nw_link
* link
= (nw_link
*)data
;
394 // Emit stats if link matches
395 if (port
->link
== link
)
396 return nw_stats_collector_emit_port_stats(daemon
, port
);
401 int nw_port_update_stats(nw_port
* port
) {
403 return nw_link_update_stats(port
->link
);