]>
git.ipfire.org Git - people/ms/network.git/blob - src/networkd/link.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-netlink.h>
42 char ifname
[IFNAMSIZ
];
54 int nw_link_create(nw_link
** link
, nw_daemon
* daemon
, int ifindex
) {
55 // Allocate a new object
56 nw_link
* l
= calloc(1, sizeof(*l
));
60 // Store a reference to the daemon
61 l
->daemon
= nw_daemon_ref(daemon
);
63 // Initialize the reference counter
69 DEBUG("New link allocated (ifindex = %d)\n", l
->ifindex
);
76 static void nw_link_free(nw_link
* link
) {
77 DEBUG("Freeing link (ifindex = %d)\n", link
->ifindex
);
80 nw_daemon_unref(link
->daemon
);
83 nw_link
* nw_link_ref(nw_link
* link
) {
89 nw_link
* nw_link_unref(nw_link
* link
) {
90 if (--link
->nrefs
> 0)
97 int nw_link_ifindex(nw_link
* link
) {
103 int nw_link_has_carrier(nw_link
* link
) {
104 return link
->operstate
== IF_OPER_UP
;
107 static int nw_link_carrier_gained(nw_link
* link
) {
108 return 0; // XXX TODO
111 static int nw_link_carrier_lost(nw_link
* link
) {
112 return 0; // XXX TODO
115 static int nw_link_update_ifname(nw_link
* link
, sd_netlink_message
* message
) {
116 const char* ifname
= NULL
;
119 r
= sd_netlink_message_read_string(message
, IFLA_IFNAME
, &ifname
);
121 ERROR("Could not read link name for link %d: %m\n", link
->ifindex
);
125 // Do nothing if the name is already set
126 if (strcmp(link
->ifname
, ifname
) == 0)
129 // Otherwise update the name
130 r
= nw_string_set(link
->ifname
, ifname
);
132 ERROR("Could not set link name: %m\n");
136 DEBUG("Link %d has been renamed to '%s'\n", link
->ifindex
, link
->ifname
);
141 static int nw_link_update_mtu(nw_link
* link
, sd_netlink_message
* message
) {
143 uint32_t min_mtu
= 0;
144 uint32_t max_mtu
= 0;
148 r
= sd_netlink_message_read_u32(message
, IFLA_MTU
, &mtu
);
150 ERROR("Could not read MTU for link %d: %m\n", link
->ifindex
);
154 // Read the minimum MTU
155 r
= sd_netlink_message_read_u32(message
, IFLA_MIN_MTU
, &min_mtu
);
157 ERROR("Could not read the minimum MTU for link %d: %m\n", link
->ifindex
);
161 // Read the maximum MTU
162 r
= sd_netlink_message_read_u32(message
, IFLA_MAX_MTU
, &max_mtu
);
164 ERROR("Could not read the maximum MTU for link %d: %m\n", link
->ifindex
);
168 // Set the maximum MTU to infinity
170 max_mtu
= UINT32_MAX
;
173 link
->min_mtu
= min_mtu
;
174 link
->max_mtu
= max_mtu
;
176 // End here, if the MTU has not been changed
177 if (link
->mtu
== mtu
)
180 DEBUG("Link %d: MTU has changed to %" PRIu32
" (min: %" PRIu32
", max: %" PRIu32
")\n",
181 link
->ifindex
, link
->mtu
, link
->min_mtu
, link
->max_mtu
);
189 static int nw_link_update_flags(nw_link
* link
, sd_netlink_message
* message
) {
190 unsigned int flags
= 0;
191 uint8_t operstate
= 0;
195 r
= sd_rtnl_message_link_get_flags(message
, &flags
);
197 return DEBUG("Could not read link flags: %m\n");
202 r
= sd_netlink_message_read_u8(message
, IFLA_OPERSTATE
, &operstate
);
204 ERROR("Could not read operstate: %m\n");
208 // End here if there have been no changes
209 if (link
->flags
== flags
&& link
->operstate
== operstate
)
212 // XXX We should log any changes here
214 // Fetch current carrier state
215 const int had_carrier
= nw_link_has_carrier(link
);
217 // Store the new flags & operstate
219 link
->operstate
= operstate
;
221 // Notify if carrier was gained or lost
222 if (!had_carrier
&& nw_link_has_carrier(link
)) {
223 r
= nw_link_carrier_gained(link
);
227 } else if (had_carrier
&& !nw_link_has_carrier(link
)) {
228 r
= nw_link_carrier_lost(link
);
237 This function is called whenever anything changes, so that we can
238 update our internal link object.
240 static int nw_link_update(nw_link
* link
, sd_netlink_message
* message
) {
243 // Update the interface name
244 r
= nw_link_update_ifname(link
, message
);
249 r
= nw_link_update_mtu(link
, message
);
254 r
= nw_link_update_flags(link
, message
);
261 int nw_link_process(sd_netlink
* rtnl
, sd_netlink_message
* message
, void* data
) {
262 nw_links
* links
= NULL
;
263 nw_link
* link
= NULL
;
264 const char* ifname
= NULL
;
269 nw_daemon
* daemon
= (nw_daemon
*)data
;
272 links
= nw_daemon_links(daemon
);
278 // Check if this message could be received
279 if (sd_netlink_message_is_error(message
)) {
280 r
= sd_netlink_message_get_errno(message
);
282 ERROR("Could not receive link message: %m\n");
287 // Fetch the message type
288 r
= sd_netlink_message_get_type(message
, &type
);
290 ERROR("Could not fetch message type: %m\n");
301 ERROR("Received an unexpected message (type %u)\n", type
);
305 // Fetch the interface index
306 r
= sd_rtnl_message_link_get_ifindex(message
, &ifindex
);
308 ERROR("Could not fetch ifindex: %m\n");
312 // Check interface index
314 ERROR("Received an invalid ifindex\n");
318 // Fetch the interface name
319 r
= sd_netlink_message_read_string(message
, IFLA_IFNAME
, &ifname
);
321 ERROR("Received a netlink message without interface name: %m\n");
325 // Try finding an existing link
326 link
= nw_daemon_get_link_by_ifindex(daemon
, ifindex
);
330 // If the link doesn't exist, create it
332 r
= nw_link_create(&link
, daemon
, ifindex
);
334 ERROR("Could not create link: %m\n");
338 // Add it to the list
339 r
= nw_links_add_link(links
, link
);
344 // Import any data from the netlink message
345 r
= nw_link_update(link
, message
);
353 nw_links_drop_link(links
, link
);
363 nw_links_unref(links
);