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