Skip to content

Commit 54abf46

Browse files
committed
networkd: add basic VLAN support
1 parent 168a3f6 commit 54abf46

File tree

6 files changed

+128
-17
lines changed

6 files changed

+128
-17
lines changed

man/systemd-networkd.service.xml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,24 @@
105105
<varlistentry>
106106
<term><varname>Kind</varname></term>
107107
<listitem>
108-
<para>The netdev kind. Currently, 'bridge' and 'bond' are
109-
supported. This option is compulsory.</para>
108+
<para>The netdev kind. Currently, 'bridge', 'bond' and 'vlan'
109+
are supported. This option is compulsory.</para>
110110
</listitem>
111111
</varlistentry>
112112
</variablelist>
113+
114+
<para>The <literal>[VLAN]</literal> section only applies for netdevs of kind 'vlan',
115+
and accepts the following keys:</para>
116+
117+
<variablelist class='network-directives'>
118+
<varlistentry>
119+
<term><varname>Id</varname></term>
120+
<listitem>
121+
<para>The VLAN ID to use. This option is compulsory.</para>
122+
</listitem>
123+
</varlistentry>
124+
</variablelist>
125+
113126
</refsect2>
114127

115128
<refsect2><title>Networks</title>

src/network/networkd-gperf.gperf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Match.Name, config_parse_ifname, 0, offsetof(Networ
2323
Network.Description, config_parse_string, 0, offsetof(Network, description)
2424
Network.Bridge, config_parse_bridge, 0, offsetof(Network, bridge)
2525
Network.Bond, config_parse_bond, 0, offsetof(Network, bond)
26+
Network.VLAN, config_parse_vlan, 0, offsetof(Network, vlan)
2627
Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp)
2728
Network.Address, config_parse_address, 0, 0
2829
Network.Gateway, config_parse_gateway, 0, 0
@@ -38,3 +39,4 @@ DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Networ
3839
Netdev.Description, config_parse_string, 0, offsetof(Netdev, description)
3940
Netdev.Name, config_parse_ifname, 0, offsetof(Netdev, name)
4041
Netdev.Kind, config_parse_netdev_kind, 0, offsetof(Netdev, kind)
42+
VLAN.Id, config_parse_int, 0, offsetof(Netdev, vlanid)

src/network/networkd-link.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ static int link_enter_enslave(Link *link) {
786786

787787
link->state = LINK_STATE_ENSLAVING;
788788

789-
if (!link->network->bridge && !link->network->bond)
789+
if (!link->network->bridge && !link->network->bond && !link->network->vlan)
790790
return link_enslaved(link);
791791

792792
if (link->network->bridge) {
@@ -810,19 +810,19 @@ static int link_enter_enslave(Link *link) {
810810
link->enslaving ++;
811811
}
812812

813-
if (link->network->bond) {
813+
if (link->network->vlan) {
814814
log_struct_link(LOG_DEBUG, link,
815815
"MESSAGE=%s: enslaving by '%s'",
816-
link->network->bond->name,
817-
NETDEV(link->network->bond),
816+
link->network->vlan->name,
817+
NETDEV(link->network->vlan),
818818
NULL);
819819

820-
r = netdev_enslave(link->network->bond, link, &enslave_handler);
820+
r = netdev_enslave(link->network->vlan, link, &enslave_handler);
821821
if (r < 0) {
822822
log_struct_link(LOG_WARNING, link,
823823
"MESSAGE=%s: could not enslave by '%s': %s",
824-
link->network->bond->name, strerror(-r),
825-
NETDEV(link->network->bond),
824+
link->network->vlan->name, strerror(-r),
825+
NETDEV(link->network->vlan),
826826
NULL);
827827
link_enter_failed(link);
828828
return r;

src/network/networkd-netdev.c

Lines changed: 59 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828

2929
static const char* const netdev_kind_table[] = {
3030
[NETDEV_KIND_BRIDGE] = "bridge",
31-
[NETDEV_KIND_BOND] = "bond"
31+
[NETDEV_KIND_BOND] = "bond",
32+
[NETDEV_KIND_VLAN] = "vlan",
3233
};
3334

3435
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetdevKind);
@@ -154,13 +155,13 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
154155
return 1;
155156
}
156157

157-
static int netdev_create(Netdev *netdev) {
158+
static int netdev_create(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
158159
_cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
159160
const char *kind;
160161
int r;
161162

162163
assert(netdev);
163-
assert(netdev->state == _NETDEV_STATE_INVALID);
164+
assert(!(netdev->kind == NETDEV_KIND_VLAN) || (link && callback && netdev->vlanid >= 0));
164165
assert(netdev->name);
165166
assert(netdev->manager);
166167
assert(netdev->manager->rtnl);
@@ -173,6 +174,16 @@ static int netdev_create(Netdev *netdev) {
173174
return r;
174175
}
175176

177+
if (link) {
178+
r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex);
179+
if (r < 0) {
180+
log_error_netdev(netdev,
181+
"Could not append IFLA_LINK attribute: %s",
182+
strerror(-r));
183+
return r;
184+
}
185+
}
186+
176187
r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name);
177188
if (r < 0) {
178189
log_error_netdev(netdev,
@@ -203,6 +214,32 @@ static int netdev_create(Netdev *netdev) {
203214
return r;
204215
}
205216

217+
if (netdev->vlanid >= 0) {
218+
r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
219+
if (r < 0) {
220+
log_error_netdev(netdev,
221+
"Could not open IFLA_INFO_DATA container: %s",
222+
strerror(-r));
223+
return r;
224+
}
225+
226+
r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid);
227+
if (r < 0) {
228+
log_error_netdev(netdev,
229+
"Could not append IFLA_VLAN_ID attribute: %s",
230+
strerror(-r));
231+
return r;
232+
}
233+
234+
r = sd_rtnl_message_close_container(req);
235+
if (r < 0) {
236+
log_error_netdev(netdev,
237+
"Could not close IFLA_INFO_DATA container %s",
238+
strerror(-r));
239+
return r;
240+
}
241+
}
242+
206243
r = sd_rtnl_message_close_container(req);
207244
if (r < 0) {
208245
log_error_netdev(netdev,
@@ -211,7 +248,10 @@ static int netdev_create(Netdev *netdev) {
211248
return r;
212249
}
213250

214-
r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
251+
if (link)
252+
r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
253+
else
254+
r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL);
215255
if (r < 0) {
216256
log_error_netdev(netdev,
217257
"Could not send rtnetlink message: %s", strerror(-r));
@@ -226,6 +266,9 @@ static int netdev_create(Netdev *netdev) {
226266
}
227267

228268
int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) {
269+
if (netdev->kind == NETDEV_KIND_VLAN)
270+
return netdev_create(netdev, link, callback);
271+
229272
if (netdev->state == NETDEV_STATE_READY) {
230273
netdev_enslave_ready(netdev, link, callback);
231274
} else {
@@ -289,8 +332,9 @@ static int netdev_load_one(Manager *manager, const char *filename) {
289332
netdev->manager = manager;
290333
netdev->state = _NETDEV_STATE_INVALID;
291334
netdev->kind = _NETDEV_KIND_INVALID;
335+
netdev->vlanid = -1;
292336

293-
r = config_parse(NULL, filename, file, "Netdev\0", config_item_perf_lookup,
337+
r = config_parse(NULL, filename, file, "Netdev\0VLAN\0", config_item_perf_lookup,
294338
(void*) network_gperf_lookup, false, false, netdev);
295339
if (r < 0) {
296340
log_warning("Could not parse config file %s: %s", filename, strerror(-r));
@@ -307,6 +351,11 @@ static int netdev_load_one(Manager *manager, const char *filename) {
307351
return 0;
308352
}
309353

354+
if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid < 0) {
355+
log_warning("VLAN without Id configured in %s. Ignoring", filename);
356+
return 0;
357+
}
358+
310359
netdev->filename = strdup(filename);
311360
if (!netdev->filename)
312361
return log_oom();
@@ -317,9 +366,11 @@ static int netdev_load_one(Manager *manager, const char *filename) {
317366

318367
LIST_HEAD_INIT(netdev->callbacks);
319368

320-
r = netdev_create(netdev);
321-
if (r < 0)
322-
return r;
369+
if (netdev->kind != NETDEV_KIND_VLAN) {
370+
r = netdev_create(netdev, NULL, NULL);
371+
if (r < 0)
372+
return r;
373+
}
323374

324375
netdev = NULL;
325376

src/network/networkd-network.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,40 @@ int config_parse_bond(const char *unit,
285285

286286
return 0;
287287
}
288+
289+
int config_parse_vlan(const char *unit,
290+
const char *filename,
291+
unsigned line,
292+
const char *section,
293+
unsigned section_line,
294+
const char *lvalue,
295+
int ltype,
296+
const char *rvalue,
297+
void *data,
298+
void *userdata) {
299+
Network *network = userdata;
300+
Netdev *netdev;
301+
int r;
302+
303+
assert(filename);
304+
assert(lvalue);
305+
assert(rvalue);
306+
assert(data);
307+
308+
r = netdev_get(network->manager, rvalue, &netdev);
309+
if (r < 0) {
310+
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
311+
"VLAN is invalid, ignoring assignment: %s", rvalue);
312+
return 0;
313+
}
314+
315+
if (netdev->kind != NETDEV_KIND_VLAN) {
316+
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
317+
"Netdev is not a VLAN, ignoring assignment: %s", rvalue);
318+
return 0;
319+
}
320+
321+
network->vlan = netdev;
322+
323+
return 0;
324+
}

src/network/networkd.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct netdev_enslave_callback {
5353
typedef enum NetdevKind {
5454
NETDEV_KIND_BRIDGE,
5555
NETDEV_KIND_BOND,
56+
NETDEV_KIND_VLAN,
5657
_NETDEV_KIND_MAX,
5758
_NETDEV_KIND_INVALID = -1
5859
} NetdevKind;
@@ -74,6 +75,8 @@ struct Netdev {
7475
char *name;
7576
NetdevKind kind;
7677

78+
int vlanid;
79+
7780
Link *link;
7881
NetdevState state;
7982

@@ -94,6 +97,7 @@ struct Network {
9497
char *description;
9598
Netdev *bridge;
9699
Netdev *bond;
100+
Netdev *vlan;
97101
bool dhcp;
98102
bool dhcp_dns;
99103
bool dhcp_mtu;
@@ -258,6 +262,10 @@ int config_parse_bond(const char *unit, const char *filename, unsigned line,
258262
const char *section, unsigned section_line, const char *lvalue,
259263
int ltype, const char *rvalue, void *data, void *userdata);
260264

265+
int config_parse_vlan(const char *unit, const char *filename, unsigned line,
266+
const char *section, unsigned section_line, const char *lvalue,
267+
int ltype, const char *rvalue, void *data, void *userdata);
268+
261269
/* gperf */
262270

263271
const struct ConfigPerfItem* network_gperf_lookup(const char *key, unsigned length);

0 commit comments

Comments
 (0)