]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/port-vlan.c
config: Extend the parser to easier read/write configs
[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 struct nw_string_table 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_read_proto(nw_config* config, const char* key, void* data) {
42 nw_port_vlan_proto_t* proto = (nw_port_vlan_proto_t*)data;
43
44 const char* value = nw_config_get(config, key);
45 if (value) {
46 *proto = nw_port_vlan_proto_from_string(data);
47 if (!*proto)
48 return -errno;
49 }
50
51 return 0;
52 }
53
54 static int nw_port_vlan_write_proto(nw_config* config, const char* key, const void* data) {
55 const nw_port_vlan_proto_t* proto = (nw_port_vlan_proto_t*)data;
56
57 return nw_config_set(config, key, nw_port_vlan_proto_to_string(*proto));
58 }
59
60 static int nw_port_vlan_setup(nw_port* port) {
61 int r;
62
63 // VLAN ID
64 r = NW_CONFIG_OPTION_INT(port->config, "VLAN_ID", &port->vlan.id);
65 if (r < 0)
66 return r;
67
68 // VLAN Protocol
69 r = NW_CONFIG_OPTION(port->config, "VLAN_PROTO", &port->vlan.proto,
70 nw_port_vlan_read_proto, nw_port_vlan_write_proto);
71 if (r < 0)
72 return r;
73
74 // Parent Port
75 r = NW_CONFIG_OPTION_STRING(port->config, "VLAN_PARENT", &port->vlan.__parent_name);
76 if (r < 0)
77 return r;
78
79 return 0;
80 }
81
82 static int nw_port_vlan_create_link(nw_port* port, sd_netlink_message* m) {
83 int r;
84
85 // Set VLAN ID
86 r = sd_netlink_message_append_u16(m, IFLA_VLAN_ID, port->vlan.id);
87 if (r < 0)
88 return r;
89
90 // Set VLAN protocol
91 r = sd_netlink_message_append_u16(m, IFLA_VLAN_PROTOCOL, htobe16(port->vlan.proto));
92 if (r < 0)
93 return r;
94
95 return 0;
96 }
97
98 static int nw_port_vlan_to_json(nw_port* port, struct json_object* o) {
99 nw_port* parent = NULL;
100 int r;
101
102 // Add the VLAN ID
103 r = json_object_add_int64(o, "VLANId", port->vlan.id);
104 if (r < 0)
105 goto ERROR;
106
107 // Add the VLAN Protocol
108 r = json_object_add_string(o, "VLANProtocol",
109 nw_port_vlan_proto_to_string(port->vlan.proto));
110 if (r < 0)
111 goto ERROR;
112
113 // Fetch the parent
114 parent = nw_port_get_parent_port(port);
115 if (parent) {
116 r = json_object_add_string(o, "VLANParentPort", nw_port_name(parent));
117 if (r < 0)
118 goto ERROR;
119 }
120
121 ERROR:
122 if (parent)
123 nw_port_unref(parent);
124
125 return r;
126 }
127
128 const nw_port_info_t nw_port_info_vlan = {
129 .kind = "vlan",
130
131 // Operations
132 .ops = {
133 // Configuration
134 .setup = nw_port_vlan_setup,
135
136 .get_parent_port = nw_port_get_vlan_parent,
137
138 // Link
139 .create_link = nw_port_vlan_create_link,
140
141 // JSON
142 .to_json = nw_port_vlan_to_json,
143 },
144 };
145
146 /*
147 VLAN
148 */
149 int nw_port_get_vlan_id(nw_port* port) {
150 int r;
151
152 // Check type
153 r = nw_port_check_type(port, NW_PORT_VLAN);
154 if (r < 0)
155 return r;
156
157 return port->vlan.id;
158 }
159
160 int nw_port_set_vlan_id(nw_port* port, int id) {
161 int r;
162
163 // Check type
164 r = nw_port_check_type(port, NW_PORT_VLAN);
165 if (r < 0)
166 return r;
167
168 // Check if the VLAN ID is within range
169 if (id < NW_VLAN_ID_MIN || id > NW_VLAN_ID_MAX)
170 return -EINVAL;
171
172 // Store the ID
173 port->vlan.id = id;
174
175 DEBUG("Port %s: Set VLAN ID to %d\n", port->name, port->vlan.id);
176
177 return 0;
178 }
179
180 int nw_port_set_vlan_proto(nw_port* port, const nw_port_vlan_proto_t proto) {
181 switch (proto) {
182 case NW_VLAN_PROTO_8021Q:
183 case NW_VLAN_PROTO_8021ad:
184 port->vlan.proto = proto;
185 break;
186
187 default:
188 return -EINVAL;
189 }
190
191 return 0;
192 }
193
194 nw_port* nw_port_get_vlan_parent(nw_port* port) {
195 int r;
196
197 // Check type
198 r = nw_port_check_type(port, NW_PORT_VLAN);
199 if (r < 0)
200 return NULL;
201
202 // Try to find a reference to the parent if none exists
203 if (!port->vlan.parent && *port->vlan.__parent_name)
204 port->vlan.parent = nw_daemon_get_port_by_name(port->daemon, port->vlan.__parent_name);
205
206 if (port->vlan.parent)
207 return nw_port_ref(port->vlan.parent);
208
209 // No port found
210 return NULL;
211 }
212
213 int nw_port_set_vlan_parent(nw_port* port, nw_port* parent) {
214 int r;
215
216 // Check type
217 r = nw_port_check_type(port, NW_PORT_VLAN);
218 if (r < 0)
219 return r;
220
221 // Reset the former parent name
222 nw_string_empty(port->vlan.__parent_name);
223
224 // Dereference the former parent
225 if (port->vlan.parent) {
226 nw_port_unref(port->vlan.parent);
227 port->vlan.parent = NULL;
228 }
229
230 // Store the new parent
231 if (parent)
232 port->vlan.parent = nw_port_ref(parent);
233
234 DEBUG("Port %s: Set VLAN parent to %s\n", port->name, nw_port_name(port->vlan.parent));
235
236 return 0;
237 }