]> git.ipfire.org Git - people/ms/network.git/blame - src/networkd/port-vlan.c
config: Add string buffer type
[people/ms/network.git] / src / networkd / port-vlan.c
CommitLineData
ff886975
MT
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
d872e169
MT
21#include <linux/if_link.h>
22
240e331b
MT
23#include <systemd/sd-netlink.h>
24
ff886975
MT
25#include "config.h"
26#include "daemon.h"
e9b0614e 27#include "json.h"
ff886975
MT
28#include "logging.h"
29#include "port.h"
30#include "port-vlan.h"
31#include "string.h"
32
644eb1c8 33const nw_string_table_t nw_port_vlan_proto[] = {
d872e169 34 { NW_VLAN_PROTO_8021Q, "802.1Q" },
4db7e548 35 { NW_VLAN_PROTO_8021AD, "802.1ad" },
d872e169
MT
36 { -1, NULL },
37};
38
39NW_STRING_TABLE_LOOKUP(nw_port_vlan_proto_t, nw_port_vlan_proto)
40
082d81a3 41static int nw_port_vlan_setup(nw_port* port) {
ff886975
MT
42 int r;
43
44 // VLAN ID
082d81a3
MT
45 r = NW_CONFIG_OPTION_INT(port->config, "VLAN_ID", &port->vlan.id);
46 if (r < 0)
ff886975
MT
47 return r;
48
d872e169 49 // VLAN Protocol
7442668a
MT
50 r = NW_CONFIG_OPTION_STRING_TABLE(port->config,
51 "VLAN_PROTO", &port->vlan.proto, nw_port_vlan_proto);
082d81a3 52 if (r < 0)
d872e169
MT
53 return r;
54
ff886975 55 // Parent Port
e633147d
MT
56 r = NW_CONFIG_OPTION_STRING_BUFFER(port->config,
57 "VLAN_PARENT", port->vlan.__parent_name);
082d81a3 58 if (r < 0)
ff886975
MT
59 return r;
60
61 return 0;
62}
63
749b1a85
MT
64static 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
240e331b
MT
85static 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
d872e169
MT
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
240e331b
MT
98 return 0;
99}
100
e9b0614e
MT
101static 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
d872e169
MT
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
e9b0614e
MT
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
124ERROR:
125 if (parent)
126 nw_port_unref(parent);
127
128 return r;
129}
130
c464b5d1 131const nw_port_type_t nw_port_type_vlan = {
240e331b
MT
132 .kind = "vlan",
133
c464b5d1
MT
134 // Configuration
135 .setup = nw_port_vlan_setup,
749b1a85 136 .validate = nw_port_vlan_validate,
240e331b 137
c464b5d1 138 .get_parent_port = nw_port_get_vlan_parent,
240e331b 139
c464b5d1
MT
140 // Link
141 .create_link = nw_port_vlan_create_link,
e9b0614e 142
c464b5d1
MT
143 // JSON
144 .to_json = nw_port_vlan_to_json,
ff886975
MT
145};
146
147/*
148 VLAN
149*/
150int 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
161int 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
d872e169
MT
181int nw_port_set_vlan_proto(nw_port* port, const nw_port_vlan_proto_t proto) {
182 switch (proto) {
183 case NW_VLAN_PROTO_8021Q:
4db7e548 184 case NW_VLAN_PROTO_8021AD:
d872e169
MT
185 port->vlan.proto = proto;
186 break;
187
188 default:
189 return -EINVAL;
190 }
191
192 return 0;
193}
194
ff886975
MT
195nw_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
214int 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
d200865e 232 if (parent) {
ff886975
MT
233 port->vlan.parent = nw_port_ref(parent);
234
d200865e
MT
235 // Store the name
236 nw_string_set(port->vlan.__parent_name, nw_port_name(parent));
237 }
238
ff886975
MT
239 DEBUG("Port %s: Set VLAN parent to %s\n", port->name, nw_port_name(port->vlan.parent));
240
241 return 0;
242}