diff options
author | Tom Gundersen <teg@jklm.no> | 2014-01-22 14:49:24 +0100 |
---|---|---|
committer | Tom Gundersen <teg@jklm.no> | 2014-01-25 11:25:17 +0100 |
commit | 54abf461d6b10dc270c4bb2aeac65f240ff1c5cd (patch) | |
tree | 5589a8c4ac8b3245c7e2e816bbac6c8bf42bca9e | |
parent | 168a3f602fa2250dc0d0aab140ab91945d5f6efa (diff) |
networkd: add basic VLAN support
-rw-r--r-- | man/systemd-networkd.service.xml | 17 | ||||
-rw-r--r-- | src/network/networkd-gperf.gperf | 2 | ||||
-rw-r--r-- | src/network/networkd-link.c | 14 | ||||
-rw-r--r-- | src/network/networkd-netdev.c | 67 | ||||
-rw-r--r-- | src/network/networkd-network.c | 37 | ||||
-rw-r--r-- | src/network/networkd.h | 8 |
6 files changed, 128 insertions, 17 deletions
diff --git a/man/systemd-networkd.service.xml b/man/systemd-networkd.service.xml index 57a3a7cf71..3403a7a1a7 100644 --- a/man/systemd-networkd.service.xml +++ b/man/systemd-networkd.service.xml @@ -105,11 +105,24 @@ <varlistentry> <term><varname>Kind</varname></term> <listitem> - <para>The netdev kind. Currently, 'bridge' and 'bond' are - supported. This option is compulsory.</para> + <para>The netdev kind. Currently, 'bridge', 'bond' and 'vlan' + are supported. This option is compulsory.</para> </listitem> </varlistentry> </variablelist> + + <para>The <literal>[VLAN]</literal> section only applies for netdevs of kind 'vlan', + and accepts the following keys:</para> + + <variablelist class='network-directives'> + <varlistentry> + <term><varname>Id</varname></term> + <listitem> + <para>The VLAN ID to use. This option is compulsory.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect2> <refsect2><title>Networks</title> diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index 7181cf856a..aff23bb55d 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -23,6 +23,7 @@ Match.Name, config_parse_ifname, 0, offsetof(Networ Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_bridge, 0, offsetof(Network, bridge) Network.Bond, config_parse_bond, 0, offsetof(Network, bond) +Network.VLAN, config_parse_vlan, 0, offsetof(Network, vlan) Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 @@ -38,3 +39,4 @@ DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Networ Netdev.Description, config_parse_string, 0, offsetof(Netdev, description) Netdev.Name, config_parse_ifname, 0, offsetof(Netdev, name) Netdev.Kind, config_parse_netdev_kind, 0, offsetof(Netdev, kind) +VLAN.Id, config_parse_int, 0, offsetof(Netdev, vlanid) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f746f2dcc4..17e7047bd5 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -786,7 +786,7 @@ static int link_enter_enslave(Link *link) { link->state = LINK_STATE_ENSLAVING; - if (!link->network->bridge && !link->network->bond) + if (!link->network->bridge && !link->network->bond && !link->network->vlan) return link_enslaved(link); if (link->network->bridge) { @@ -810,19 +810,19 @@ static int link_enter_enslave(Link *link) { link->enslaving ++; } - if (link->network->bond) { + if (link->network->vlan) { log_struct_link(LOG_DEBUG, link, "MESSAGE=%s: enslaving by '%s'", - link->network->bond->name, - NETDEV(link->network->bond), + link->network->vlan->name, + NETDEV(link->network->vlan), NULL); - r = netdev_enslave(link->network->bond, link, &enslave_handler); + r = netdev_enslave(link->network->vlan, link, &enslave_handler); if (r < 0) { log_struct_link(LOG_WARNING, link, "MESSAGE=%s: could not enslave by '%s': %s", - link->network->bond->name, strerror(-r), - NETDEV(link->network->bond), + link->network->vlan->name, strerror(-r), + NETDEV(link->network->vlan), NULL); link_enter_failed(link); return r; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 2d1cef112b..1a6eebe1a7 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -28,7 +28,8 @@ static const char* const netdev_kind_table[] = { [NETDEV_KIND_BRIDGE] = "bridge", - [NETDEV_KIND_BOND] = "bond" + [NETDEV_KIND_BOND] = "bond", + [NETDEV_KIND_VLAN] = "vlan", }; 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 return 1; } -static int netdev_create(Netdev *netdev) { +static int netdev_create(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) { _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL; const char *kind; int r; assert(netdev); - assert(netdev->state == _NETDEV_STATE_INVALID); + assert(!(netdev->kind == NETDEV_KIND_VLAN) || (link && callback && netdev->vlanid >= 0)); assert(netdev->name); assert(netdev->manager); assert(netdev->manager->rtnl); @@ -173,6 +174,16 @@ static int netdev_create(Netdev *netdev) { return r; } + if (link) { + r = sd_rtnl_message_append_u32(req, IFLA_LINK, link->ifindex); + if (r < 0) { + log_error_netdev(netdev, + "Could not append IFLA_LINK attribute: %s", + strerror(-r)); + return r; + } + } + r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name); if (r < 0) { log_error_netdev(netdev, @@ -203,6 +214,32 @@ static int netdev_create(Netdev *netdev) { return r; } + if (netdev->vlanid >= 0) { + r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA); + if (r < 0) { + log_error_netdev(netdev, + "Could not open IFLA_INFO_DATA container: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_append_u16(req, IFLA_VLAN_ID, netdev->vlanid); + if (r < 0) { + log_error_netdev(netdev, + "Could not append IFLA_VLAN_ID attribute: %s", + strerror(-r)); + return r; + } + + r = sd_rtnl_message_close_container(req); + if (r < 0) { + log_error_netdev(netdev, + "Could not close IFLA_INFO_DATA container %s", + strerror(-r)); + return r; + } + } + r = sd_rtnl_message_close_container(req); if (r < 0) { log_error_netdev(netdev, @@ -211,7 +248,10 @@ static int netdev_create(Netdev *netdev) { return r; } - r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL); + if (link) + r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL); + else + r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL); if (r < 0) { log_error_netdev(netdev, "Could not send rtnetlink message: %s", strerror(-r)); @@ -226,6 +266,9 @@ static int netdev_create(Netdev *netdev) { } int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) { + if (netdev->kind == NETDEV_KIND_VLAN) + return netdev_create(netdev, link, callback); + if (netdev->state == NETDEV_STATE_READY) { netdev_enslave_ready(netdev, link, callback); } else { @@ -289,8 +332,9 @@ static int netdev_load_one(Manager *manager, const char *filename) { netdev->manager = manager; netdev->state = _NETDEV_STATE_INVALID; netdev->kind = _NETDEV_KIND_INVALID; + netdev->vlanid = -1; - r = config_parse(NULL, filename, file, "Netdev\0", config_item_perf_lookup, + r = config_parse(NULL, filename, file, "Netdev\0VLAN\0", config_item_perf_lookup, (void*) network_gperf_lookup, false, false, netdev); if (r < 0) { 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) { return 0; } + if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid < 0) { + log_warning("VLAN without Id configured in %s. Ignoring", filename); + return 0; + } + netdev->filename = strdup(filename); if (!netdev->filename) return log_oom(); @@ -317,9 +366,11 @@ static int netdev_load_one(Manager *manager, const char *filename) { LIST_HEAD_INIT(netdev->callbacks); - r = netdev_create(netdev); - if (r < 0) - return r; + if (netdev->kind != NETDEV_KIND_VLAN) { + r = netdev_create(netdev, NULL, NULL); + if (r < 0) + return r; + } netdev = NULL; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index e703294731..2a720349a0 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -285,3 +285,40 @@ int config_parse_bond(const char *unit, return 0; } + +int config_parse_vlan(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + Netdev *netdev; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = netdev_get(network->manager, rvalue, &netdev); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "VLAN is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (netdev->kind != NETDEV_KIND_VLAN) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Netdev is not a VLAN, ignoring assignment: %s", rvalue); + return 0; + } + + network->vlan = netdev; + + return 0; +} diff --git a/src/network/networkd.h b/src/network/networkd.h index 2323e3db85..22dcbd0987 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -53,6 +53,7 @@ struct netdev_enslave_callback { typedef enum NetdevKind { NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, + NETDEV_KIND_VLAN, _NETDEV_KIND_MAX, _NETDEV_KIND_INVALID = -1 } NetdevKind; @@ -74,6 +75,8 @@ struct Netdev { char *name; NetdevKind kind; + int vlanid; + Link *link; NetdevState state; @@ -94,6 +97,7 @@ struct Network { char *description; Netdev *bridge; Netdev *bond; + Netdev *vlan; bool dhcp; bool dhcp_dns; bool dhcp_mtu; @@ -258,6 +262,10 @@ int config_parse_bond(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_vlan(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + /* gperf */ const struct ConfigPerfItem* network_gperf_lookup(const char *key, unsigned length); |