]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/links.c
Makefile: Fix typo in localstatedir
[people/ms/network.git] / src / networkd / links.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 #include <string.h>
24 #include <sys/queue.h>
25
26 #include "daemon.h"
27 #include "logging.h"
28 #include "link.h"
29 #include "links.h"
30
31 struct nw_links_entry {
32 nw_link* link;
33
34 // Link to the other entries
35 STAILQ_ENTRY(nw_links_entry) nodes;
36 };
37
38 struct nw_links {
39 nw_daemon* daemon;
40 int nrefs;
41
42 // Link Entries
43 STAILQ_HEAD(entries, nw_links_entry) entries;
44
45 // A counter of the link entries
46 unsigned int num;
47 };
48
49 int nw_links_create(nw_links** links, nw_daemon* daemon) {
50 nw_links* l = calloc(1, sizeof(*l));
51 if (!l)
52 return 1;
53
54 // Store a reference to the daemon
55 l->daemon = nw_daemon_ref(daemon);
56
57 // Initialize the reference counter
58 l->nrefs = 1;
59
60 // Initialize entries
61 STAILQ_INIT(&l->entries);
62
63 // Reference the pointer
64 *links = l;
65
66 return 0;
67 }
68
69 static void nw_links_free(nw_links* links) {
70 struct nw_links_entry* entry = NULL;
71
72 while (!STAILQ_EMPTY(&links->entries)) {
73 entry = STAILQ_FIRST(&links->entries);
74
75 // Dereference the zone
76 nw_link_unref(entry->link);
77
78 // Remove the entry from the list
79 STAILQ_REMOVE_HEAD(&links->entries, nodes);
80
81 // Free the entry
82 free(entry);
83 }
84
85 if (links->daemon)
86 nw_daemon_unref(links->daemon);
87 }
88
89 nw_links* nw_links_ref(nw_links* links) {
90 links->nrefs++;
91
92 return links;
93 }
94
95 nw_links* nw_links_unref(nw_links* links) {
96 if (--links->nrefs > 0)
97 return links;
98
99 nw_links_free(links);
100 return NULL;
101 }
102
103 static struct nw_links_entry* nw_links_find_link(nw_links* links, const int ifindex) {
104 struct nw_links_entry* entry = NULL;
105
106 STAILQ_FOREACH(entry, &links->entries, nodes) {
107 if (nw_link_ifindex(entry->link) == ifindex)
108 return entry;
109 }
110
111 // No match found
112 return NULL;
113 }
114
115 int nw_links_add_link(nw_links* links, struct nw_link* link) {
116 // Allocate a new entry
117 struct nw_links_entry* entry = calloc(1, sizeof(*entry));
118 if (!entry)
119 return 1;
120
121 // Reference the link
122 entry->link = nw_link_ref(link);
123
124 // Add it to the list
125 STAILQ_INSERT_TAIL(&links->entries, entry, nodes);
126
127 // Increment the counter
128 links->num++;
129
130 return 0;
131 }
132
133 void nw_links_drop_link(nw_links* links, struct nw_link* link) {
134 struct nw_links_entry* entry = NULL;
135
136 entry = nw_links_find_link(links, nw_link_ifindex(link));
137 if (!entry)
138 return;
139
140 DEBUG("Dropping link %d\n", nw_link_ifindex(entry->link));
141
142 STAILQ_REMOVE(&links->entries, entry, nw_links_entry, nodes);
143 links->num--;
144
145 // Drop link from all ports
146 nw_daemon_ports_walk(links->daemon, __nw_port_drop_link, link);
147
148 // Drop link from all zones
149 nw_daemon_zones_walk(links->daemon, __nw_zone_drop_link, link);
150 }
151
152 int nw_links_enumerate(nw_links* links) {
153 sd_netlink_message* req = NULL;
154 sd_netlink_message* res = NULL;
155 int r;
156
157 sd_netlink* rtnl = nw_daemon_get_rtnl(links->daemon);
158 if (!rtnl)
159 return 1;
160
161 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
162 if (r < 0)
163 return 1;
164
165 r = sd_netlink_message_set_request_dump(req, 1);
166 if (r < 0)
167 return 1;
168
169 r = sd_netlink_call(rtnl, req, 0, &res);
170 if (r < 0)
171 return 1;
172
173 sd_netlink_message* m = res;
174
175 // Iterate through all replies
176 do {
177 r = nw_link_process(rtnl, m, links->daemon);
178 if (r)
179 goto ERROR;
180 } while ((m = sd_netlink_message_next(m)));
181
182 ERROR:
183 if (m)
184 sd_netlink_message_unref(m);
185 if (req)
186 sd_netlink_message_unref(req);
187 if (res)
188 sd_netlink_message_unref(res);
189
190 return r;
191 }
192
193 nw_link* nw_links_get_by_ifindex(nw_links* links, int ifindex) {
194 struct nw_links_entry* entry = NULL;
195
196 entry = nw_links_find_link(links, ifindex);
197 if (!entry)
198 return NULL;
199
200 return nw_link_ref(entry->link);
201 }
202
203 nw_link* nw_links_get_by_name(nw_links* links, const char* name) {
204 struct nw_links_entry* entry = NULL;
205
206 STAILQ_FOREACH(entry, &links->entries, nodes) {
207 const char* n = nw_link_ifname(entry->link);
208
209 if (strcmp(name, n) == 0)
210 return nw_link_ref(entry->link);
211 }
212
213 // No match found
214 return NULL;
215 }