]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/link.c
networkd: Only add link if we created it
[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 <stddef.h>
22 #include <stdlib.h>
23
24 #include <systemd/sd-netlink.h>
25
26 #include "daemon.h"
27 #include "link.h"
28 #include "links.h"
29 #include "logging.h"
30
31 struct nw_link {
32 struct nw_daemon* daemon;
33 int nrefs;
34
35 // Interface Index
36 int ifindex;
37 };
38
39 int nw_link_create(struct nw_link** link, struct nw_daemon* daemon, int ifindex) {
40 // Allocate a new object
41 struct nw_link* l = calloc(1, sizeof(*l));
42 if (!l)
43 return 1;
44
45 // Store a reference to the daemon
46 l->daemon = nw_daemon_ref(daemon);
47
48 // Initialize the reference counter
49 l->nrefs = 1;
50
51 // Store the ifindex
52 l->ifindex = ifindex;
53
54 DEBUG("New link allocated (ifindex = %d)\n", l->ifindex);
55
56 *link = l;
57
58 return 0;
59 }
60
61 static void nw_link_free(struct nw_link* link) {
62 DEBUG("Freeing link (ifindex = %d)\n", link->ifindex);
63
64 if (link->daemon)
65 nw_daemon_unref(link->daemon);
66 }
67
68 struct nw_link* nw_link_ref(struct nw_link* link) {
69 link->nrefs++;
70
71 return link;
72 }
73
74 struct nw_link* nw_link_unref(struct nw_link* link) {
75 if (--link->nrefs > 0)
76 return link;
77
78 nw_link_free(link);
79 return NULL;
80 }
81
82 int nw_link_ifindex(struct nw_link* link) {
83 return link->ifindex;
84 }
85
86 int nw_link_process(sd_netlink* rtnl, sd_netlink_message* message, void* data) {
87 struct nw_links* links = NULL;
88 struct nw_link* link = NULL;
89 const char* ifname = NULL;
90 int ifindex;
91 uint16_t type;
92 int r;
93
94 struct nw_daemon* daemon = (struct nw_daemon*)data;
95
96 // Fetch links
97 links = nw_daemon_links(daemon);
98 if (!links) {
99 r = 1;
100 goto ERROR;
101 }
102
103 // Check if this message could be received
104 if (sd_netlink_message_is_error(message)) {
105 r = sd_netlink_message_get_errno(message);
106 if (r < 0)
107 ERROR("Could not receive link message: %m\n");
108
109 goto IGNORE;
110 }
111
112 // Fetch the message type
113 r = sd_netlink_message_get_type(message, &type);
114 if (r < 0) {
115 ERROR("Could not fetch message type: %m\n");
116 goto IGNORE;
117 }
118
119 // Check type
120 switch (type) {
121 case RTM_NEWLINK:
122 case RTM_DELLINK:
123 break;
124
125 default:
126 ERROR("Received an unexpected message (type %u)\n", type);
127 goto IGNORE;
128 }
129
130 // Fetch the interface index
131 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
132 if (r < 0) {
133 ERROR("Could not fetch ifindex: %m\n");
134 goto IGNORE;
135 }
136
137 // Check interface index
138 if (ifindex <= 0) {
139 ERROR("Received an invalid ifindex\n");
140 goto IGNORE;
141 }
142
143 // Fetch the interface name
144 r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
145 if (r < 0) {
146 ERROR("Received a netlink message without interface name: %m\n");
147 goto IGNORE;
148 }
149
150 // Try finding an existing link
151 link = nw_daemon_get_link_by_ifindex(daemon, ifindex);
152
153 switch (type) {
154 case RTM_NEWLINK:
155 // If the link doesn't exist, create it
156 if (!link) {
157 r = nw_link_create(&link, daemon, ifindex);
158 if (r) {
159 ERROR("Could not create link: %m\n");
160 goto ERROR;
161 }
162
163 // Add it to the list
164 r = nw_links_add_link(links, link);
165 if (r)
166 goto ERROR;
167 }
168
169 // TODO Import any data from the netlink message
170
171 break;
172
173 case RTM_DELLINK:
174 if (link)
175 nw_links_drop_link(links, link);
176
177 break;
178 }
179
180 IGNORE:
181 r = 0;
182
183 ERROR:
184 if (links)
185 nw_links_unref(links);
186 if (link)
187 nw_link_unref(link);
188
189 return r;
190 }