]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/port-vlan.c
Makefile: Fix typo in localstatedir
[people/ms/network.git] / src / networkd / port-vlan.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 <linux/if_link.h>
22
23 #include <systemd/sd-netlink.h>
24
25 #include "config.h"
26 #include "daemon.h"
27 #include "json.h"
28 #include "logging.h"
29 #include "port.h"
30 #include "port-vlan.h"
31 #include "string.h"
32
33 const nw_string_table_t nw_port_vlan_proto[] = {
34 { NW_VLAN_PROTO_8021Q, "802.1Q" },
35 { NW_VLAN_PROTO_8021AD, "802.1ad" },
36 { -1, NULL },
37 };
38
39 NW_STRING_TABLE_LOOKUP(nw_port_vlan_proto_t, nw_port_vlan_proto)
40
41 static int nw_port_vlan_setup(nw_port* port) {
42 int r;
43
44 // VLAN ID
45 r = NW_CONFIG_OPTION_INT(port->config, "VLAN_ID", &port->vlan.id);
46 if (r < 0)
47 return r;
48
49 // VLAN Protocol
50 r = NW_CONFIG_OPTION_STRING_TABLE(port->config,
51 "VLAN_PROTO", &port->vlan.proto, nw_port_vlan_proto);
52 if (r < 0)
53 return r;
54
55 // Parent Port
56 r = NW_CONFIG_OPTION_STRING_BUFFER(port->config,
57 "VLAN_PARENT", port->vlan.__parent_name);
58 if (r < 0)
59 return r;
60
61 return 0;
62 }
63
64 static int nw_port_vlan_validate(nw_port* port) {
65 // Check if the VLAN ID is within range
66 if (port->vlan.id < NW_VLAN_ID_MIN || port->vlan.id > NW_VLAN_ID_MAX) {
67 ERROR("%s: Invalid VLAN ID %d\n", port->name, port->vlan.id);
68 return 1;
69 }
70
71 // Validate protocol
72 switch (port->vlan.proto) {
73 case NW_VLAN_PROTO_8021Q:
74 case NW_VLAN_PROTO_8021AD:
75 break;
76
77 default:
78 ERROR("%p: Invalid VLAN protocol\n", port->name);
79 return 1;
80 }
81
82 return 0;
83 }
84
85 static int nw_port_vlan_create_link(nw_port* port, sd_netlink_message* m) {
86 int r;
87
88 // Set VLAN ID
89 r = sd_netlink_message_append_u16(m, IFLA_VLAN_ID, port->vlan.id);
90 if (r < 0)
91 return r;
92
93 // Set VLAN protocol
94 r = sd_netlink_message_append_u16(m, IFLA_VLAN_PROTOCOL, htobe16(port->vlan.proto));
95 if (r < 0)
96 return r;
97
98 return 0;
99 }
100
101 static int nw_port_vlan_to_json(nw_port* port, struct json_object* o) {
102 nw_port* parent = NULL;
103 int r;
104
105 // Add the VLAN ID
106 r = json_object_add_int64(o, "VLANId", port->vlan.id);
107 if (r < 0)
108 goto ERROR;
109
110 // Add the VLAN Protocol
111 r = json_object_add_string(o, "VLANProtocol",
112 nw_port_vlan_proto_to_string(port->vlan.proto));
113 if (r < 0)
114 goto ERROR;
115
116 // Fetch the parent
117 parent = nw_port_get_parent_port(port);
118 if (parent) {
119 r = json_object_add_string(o, "VLANParentPort", nw_port_name(parent));
120 if (r < 0)
121 goto ERROR;
122 }
123
124 ERROR:
125 if (parent)
126 nw_port_unref(parent);
127
128 return r;
129 }
130
131 const nw_port_type_t nw_port_type_vlan = {
132 .kind = "vlan",
133
134 // Configuration
135 .setup = nw_port_vlan_setup,
136 .validate = nw_port_vlan_validate,
137
138 .get_parent_port = nw_port_get_vlan_parent,
139
140 // Link
141 .create_link = nw_port_vlan_create_link,
142
143 // JSON
144 .to_json = nw_port_vlan_to_json,
145 };
146
147 /*
148 VLAN
149 */
150 int nw_port_get_vlan_id(nw_port* port) {
151 int r;
152
153 // Check type
154 r = nw_port_check_type(port, NW_PORT_VLAN);
155 if (r < 0)
156 return r;
157
158 return port->vlan.id;
159 }
160
161 int nw_port_set_vlan_id(nw_port* port, int id) {
162 int r;
163
164 // Check type
165 r = nw_port_check_type(port, NW_PORT_VLAN);
166 if (r < 0)
167 return r;
168
169 // Check if the VLAN ID is within range
170 if (id < NW_VLAN_ID_MIN || id > NW_VLAN_ID_MAX)
171 return -EINVAL;
172
173 // Store the ID
174 port->vlan.id = id;
175
176 DEBUG("Port %s: Set VLAN ID to %d\n", port->name, port->vlan.id);
177
178 return 0;
179 }
180
181 int nw_port_set_vlan_proto(nw_port* port, const nw_port_vlan_proto_t proto) {
182 switch (proto) {
183 case NW_VLAN_PROTO_8021Q:
184 case NW_VLAN_PROTO_8021AD:
185 port->vlan.proto = proto;
186 break;
187
188 default:
189 return -EINVAL;
190 }
191
192 return 0;
193 }
194
195 nw_port* nw_port_get_vlan_parent(nw_port* port) {
196 int r;
197
198 // Check type
199 r = nw_port_check_type(port, NW_PORT_VLAN);
200 if (r < 0)
201 return NULL;
202
203 // Try to find a reference to the parent if none exists
204 if (!port->vlan.parent && *port->vlan.__parent_name)
205 port->vlan.parent = nw_daemon_get_port_by_name(port->daemon, port->vlan.__parent_name);
206
207 if (port->vlan.parent)
208 return nw_port_ref(port->vlan.parent);
209
210 // No port found
211 return NULL;
212 }
213
214 int nw_port_set_vlan_parent(nw_port* port, nw_port* parent) {
215 int r;
216
217 // Check type
218 r = nw_port_check_type(port, NW_PORT_VLAN);
219 if (r < 0)
220 return r;
221
222 // Reset the former parent name
223 nw_string_empty(port->vlan.__parent_name);
224
225 // Dereference the former parent
226 if (port->vlan.parent) {
227 nw_port_unref(port->vlan.parent);
228 port->vlan.parent = NULL;
229 }
230
231 // Store the new parent
232 if (parent) {
233 port->vlan.parent = nw_port_ref(parent);
234
235 // Store the name
236 nw_string_set(port->vlan.__parent_name, nw_port_name(parent));
237 }
238
239 DEBUG("Port %s: Set VLAN parent to %s\n", port->name, nw_port_name(port->vlan.parent));
240
241 return 0;
242 }