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>
34 #include "port-bonding.h"
35 #include "port-dummy.h"
36 #include "port-vlan.h"
37 #include "stats-collector.h"
40 static const nw_string_table_t nw_port_type_id
[] = {
41 { NW_PORT_BONDING
, "bonding" },
42 { NW_PORT_DUMMY
, "dummy" },
43 { NW_PORT_VLAN
, "vlan" },
47 NW_STRING_TABLE_LOOKUP(nw_port_type_id_t
, nw_port_type_id
)
49 static void nw_port_free(nw_port
* port
) {
51 nw_link_unref(port
->link
);
53 nw_config_unref(port
->config
);
55 nw_daemon_unref(port
->daemon
);
60 static int nw_port_set_link(nw_port
* port
, nw_link
* link
) {
61 // Do nothing if the same link is being re-assigned
62 if (port
->link
== link
)
65 // Dereference the former link if set
67 nw_link_unref(port
->link
);
71 port
->link
= nw_link_ref(link
);
73 DEBUG("Port %s: Assigned link %d\n", port
->name
, nw_link_ifindex(port
->link
));
75 // Or clear the pointer if no link has been provided
79 DEBUG("Port %s: Removed link\n", port
->name
);
85 static int nw_port_setup(nw_port
* port
) {
90 link
= nw_daemon_get_link_by_name(port
->daemon
, port
->name
);
92 r
= nw_port_set_link(port
, link
);
97 // Generate a random Ethernet address
98 r
= nw_address_generate(&port
->address
);
100 ERROR("Could not generate an Ethernet address: %s\n", strerror(-r
));
105 r
= NW_CONFIG_OPTION_ADDRESS(port
->config
, "ADDRESS", &port
->address
);
109 // Call any custom initialization
110 if (NW_PORT_TYPE(port
)->setup
) {
111 r
= NW_PORT_TYPE(port
)->setup(port
);
116 // Parse the configuration
117 r
= nw_config_options_read(port
->config
);
119 ERROR("Could not read configuration for port %s: %s\n", port
->name
, strerror(-r
));
130 static int nw_port_validate(nw_port
* port
) {
133 // Validate the port configuration
134 if (NW_PORT_TYPE(port
)->validate
) {
135 r
= NW_PORT_TYPE(port
)->validate(port
);
137 ERROR("Could not check configuration for %s: %s\n", port
->name
, strerror(-r
));
143 int nw_port_create(nw_port
** port
, nw_daemon
* daemon
,
144 const nw_port_type_id_t type
, const char* name
, nw_config
* config
) {
147 // Allocate a new object
148 nw_port
* p
= calloc(1, sizeof(*p
));
152 // Store a reference to the daemon
153 p
->daemon
= nw_daemon_ref(daemon
);
155 // Initialize reference counter
160 case NW_PORT_BONDING
:
161 p
->type
= &nw_port_type_bonding
;
165 p
->type
= &nw_port_type_dummy
;
169 p
->type
= &nw_port_type_vlan
;
174 r
= nw_string_set(p
->name
, name
);
178 // Copy the configuration
179 r
= nw_config_copy(config
, &p
->config
);
184 r
= nw_port_setup(p
);
188 // Validate the configuration
189 r
= nw_port_validate(p
);
191 // Configuration is valid
195 // Configuration is invalid
197 ERROR("%s: Invalid configuration\n", p
->name
);
213 int nw_port_create_from_config(nw_port
** port
, nw_daemon
* daemon
,
214 const char* name
, const char* path
) {
215 nw_config
* config
= NULL
;
218 // Initialize the configuration
219 r
= nw_config_create(&config
, path
);
224 const char* type
= nw_config_get(config
, "TYPE");
226 ERROR("Port configuration %s has no TYPE\n", path
);
232 r
= nw_port_create(port
, daemon
, nw_port_type_id_from_string(type
), name
, config
);
238 nw_config_unref(config
);
243 nw_port
* nw_port_ref(nw_port
* port
) {
249 nw_port
* nw_port_unref(nw_port
* port
) {
250 if (--port
->nrefs
> 0)
258 This is a helper function for when we pass a reference to the event loop
259 it will have to dereference the port instance later.
261 static void __nw_port_unref(void* data
) {
262 nw_port
* port
= (nw_port
*)data
;
267 int nw_port_destroy(nw_port
* port
) {
270 DEBUG("Destroying port %s\n", port
->name
);
272 // Destroy the physical link (if exists)
274 r
= nw_link_destroy(port
->link
);
279 // Dereference the port from other ports
280 r
= nw_daemon_ports_walk(port
->daemon
, __nw_port_drop_port
, port
);
284 // Dereference the port from other zones
285 r
= nw_daemon_zones_walk(port
->daemon
, __nw_zone_drop_port
, port
);
289 // Destroy the configuration
290 r
= nw_config_destroy(port
->config
);
297 int __nw_port_drop_port(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
298 nw_port
* dropped_port
= (nw_port
*)data
;
301 switch (port
->type
->id
) {
303 if (port
->vlan
.parent
== dropped_port
) {
304 r
= nw_port_set_vlan_parent(port
, NULL
);
310 case NW_PORT_BONDING
:
318 int nw_port_save(nw_port
* port
) {
321 // Write out the configuration
322 r
= nw_config_options_write(port
->config
);
326 // Write the configuration
327 r
= nw_config_write(port
->config
);
334 ERROR("Could not save configuration for port %s: %s\n", port
->name
, strerror(-r
));
339 const char* nw_port_name(nw_port
* port
) {
343 char* nw_port_bus_path(nw_port
* port
) {
347 // Encode the bus path
348 r
= sd_bus_path_encode("/org/ipfire/network1/port", port
->name
, &p
);
355 int __nw_port_set_link(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
356 nw_link
* link
= (nw_link
*)data
;
358 // Fetch the link name
359 const char* ifname
= nw_link_ifname(link
);
361 ERROR("Link does not have a name set\n");
365 // Set link if the name matches
366 if (strcmp(port
->name
, ifname
) == 0)
367 return nw_port_set_link(port
, link
);
369 // If we have the link set but the name did not match, we will remove it
370 else if (port
->link
== link
)
371 return nw_port_set_link(port
, NULL
);
376 int __nw_port_drop_link(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
377 nw_link
* link
= (nw_link
*)data
;
379 // Drop the link if it matches
380 if (port
->link
== link
)
381 return nw_port_set_link(port
, NULL
);
386 static nw_link
* nw_port_get_link(nw_port
* port
) {
387 // Fetch the link if not set
389 port
->link
= nw_daemon_get_link_by_name(port
->daemon
, port
->name
);
394 return nw_link_ref(port
->link
);
397 const nw_address_t
* nw_port_get_address(nw_port
* port
) {
398 return &port
->address
;
401 static int nw_port_is_disabled(nw_port
* port
) {
402 return nw_config_get_bool(port
->config
, "DISABLED");
405 nw_port
* nw_port_get_parent_port(nw_port
* port
) {
406 if (!NW_PORT_TYPE(port
)->get_parent_port
)
409 return NW_PORT_TYPE(port
)->get_parent_port(port
);
412 static nw_link
* nw_port_get_parent_link(nw_port
* port
) {
413 nw_port
* parent
= NULL
;
414 nw_link
* link
= NULL
;
417 parent
= nw_port_get_parent_port(port
);
422 link
= nw_port_get_link(parent
);
426 nw_port_unref(parent
);
431 static int __nw_port_create_link(sd_netlink
* rtnl
, sd_netlink_message
* m
, void* data
) {
432 nw_port
* port
= (nw_port
*)data
;
435 // Check if the operation was successful
436 r
= sd_netlink_message_get_errno(m
);
438 ERROR("Could not create port %s: %s\n", port
->name
, strerror(-r
));
439 // XXX We should extract the error message
444 DEBUG("Successfully created %s\n", port
->name
);
449 static int nw_port_create_link(nw_port
* port
) {
450 sd_netlink_message
* m
= NULL
;
451 nw_link
* link
= NULL
;
454 sd_netlink
* rtnl
= nw_daemon_get_rtnl(port
->daemon
);
456 DEBUG("Creating port %s...\n", port
->name
);
459 if (!NW_PORT_TYPE(port
)->kind
) {
460 ERROR("Port type has no kind\n");
466 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
468 ERROR("Could not create netlink message: %m\n");
473 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, port
->name
);
475 ERROR("Could not set port name: %s\n", strerror(-r
));
479 // XXX Set common things like MTU, etc.
481 // Set Ethernet address
482 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, &port
->address
);
484 ERROR("Could not set MAC address: %s\n", strerror(-r
));
488 // Fetch the parent link
489 link
= nw_port_get_parent_link(port
);
491 r
= sd_netlink_message_append_u32(m
, IFLA_LINK
, nw_link_ifindex(link
));
496 // Open an IFLA_LINKINFO container
497 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
501 // Run the custom setup
502 if (NW_PORT_TYPE(port
)->create_link
) {
503 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, NW_PORT_TYPE(port
)->kind
);
505 ERROR("Could not open IFLA_INFO_DATA container: %s\n", strerror(-r
));
509 r
= NW_PORT_TYPE(port
)->create_link(port
, m
);
511 ERROR("Could not create port %s: %m\n", port
->name
);
515 // Close the container
516 r
= sd_netlink_message_close_container(m
);
520 // Just set IFLA_INFO_KIND if there is no custom function
522 r
= sd_netlink_message_append_string(m
, IFLA_INFO_KIND
, NW_PORT_TYPE(port
)->kind
);
527 // Close the container
528 r
= sd_netlink_message_close_container(m
);
533 r
= sd_netlink_call_async(rtnl
, NULL
, m
, __nw_port_create_link
,
534 __nw_port_unref
, nw_port_ref(port
), -1, NULL
);
536 ERROR("Could not send netlink message: %s\n", strerror(-r
));
544 sd_netlink_message_unref(m
);
551 int nw_port_reconfigure(nw_port
* port
) {
554 // If the port is disabled, we will try to destroy it
555 if (nw_port_is_disabled(port
)) {
557 r
= nw_link_destroy(port
->link
);
565 // If there is no link, we will try to create it
567 return nw_port_create_link(port
);
574 int nw_port_has_carrier(nw_port
* port
) {
578 return nw_link_has_carrier(port
->link
);
585 const struct rtnl_link_stats64
* nw_port_get_stats64(nw_port
* port
) {
589 return nw_link_get_stats64(port
->link
);
592 int __nw_port_update_stats(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
593 nw_link
* link
= (nw_link
*)data
;
595 // Emit stats if link matches
596 if (port
->link
== link
)
597 return nw_stats_collector_emit_port_stats(daemon
, port
);
602 int nw_port_update_stats(nw_port
* port
) {
604 return nw_link_update_stats(port
->link
);
609 int nw_port_check_type(nw_port
* port
, const nw_port_type_id_t type
) {
610 if (port
->type
->id
== type
)
620 int nw_port_to_json(nw_port
* port
, struct json_object
** object
) {
621 char* address
= NULL
;
624 // Create a new JSON object
625 struct json_object
* o
= json_object_new_object();
632 r
= json_object_add_string(o
, "Name", port
->name
);
637 r
= json_object_add_string(o
, "Type", nw_port_type_id_to_string(port
->type
->id
));
642 address
= nw_address_to_string(&port
->address
);
644 r
= json_object_add_string(o
, "Address", address
);
650 if (NW_PORT_TYPE(port
)->to_json
) {
651 r
= NW_PORT_TYPE(port
)->to_json(port
, o
);
659 // Return a reference to the created object
660 *object
= json_object_ref(o
);
666 json_object_unref(o
);