chiark / gitweb /
networkd: VLAN - allow multiple vlans to be created on a link
authorTom Gundersen <teg@jklm.no>
Mon, 10 Feb 2014 17:41:54 +0000 (18:41 +0100)
committerTom Gundersen <teg@jklm.no>
Mon, 10 Feb 2014 18:00:17 +0000 (19:00 +0100)
Also limit the range of vlan ids. Other implementations and
documentation use the ranges {0,1}-{4094,4095}, but we use
the one accepted by the kernel: 0-4094.

Reported-by: Oleksii Shevchuk <alxchk@gmail.com>
man/systemd-networkd.service.xml
src/network/networkd-gperf.gperf
src/network/networkd-link.c
src/network/networkd-netdev.c
src/network/networkd-network.c
src/network/networkd.h

index e5499d66d7a3b89c097e1e96c3f63f640fc08d61..1b1ea4c5fe8735be0af7e32bd51b8ca4ce14e2a1 100644 (file)
                                 <varlistentry>
                                         <term><varname>Id</varname></term>
                                         <listitem>
                                 <varlistentry>
                                         <term><varname>Id</varname></term>
                                         <listitem>
-                                                <para>The VLAN ID to use. This option is compulsory.</para>
+                                                <para>The VLAN ID to use. An integer in the range 0-4094.
+                                                This option is compulsory.</para>
                                         </listitem>
                                 </varlistentry>
                         </variablelist>
                                         </listitem>
                                 </varlistentry>
                         </variablelist>
                                 <varlistentry>
                                         <term><varname>Bridge</varname></term>
                                         <listitem>
                                 <varlistentry>
                                         <term><varname>Bridge</varname></term>
                                         <listitem>
-                                                <para>The name of the bridge to add the configured link to.</para>
+                                                <para>The name of the bridge to add the link to.</para>
                                         </listitem>
                                 </varlistentry>
                                 <varlistentry>
                                         <term><varname>Bond</varname></term>
                                         <listitem>
                                         </listitem>
                                 </varlistentry>
                                 <varlistentry>
                                         <term><varname>Bond</varname></term>
                                         <listitem>
-                                                <para>The name of the bond to add the configured link to.</para>
+                                                <para>The name of the bond to add the link to.</para>
+                                        </listitem>
+                                </varlistentry>
+                                <varlistentry>
+                                        <term><varname>VLAN</varname></term>
+                                        <listitem>
+                                                <para>The name of a VLAN to create on the link. This option
+                                                may be specified more than once.</para>
                                         </listitem>
                                 </varlistentry>
                         </variablelist>
                                         </listitem>
                                 </varlistentry>
                         </variablelist>
index 37bb8db149ebd1de3919cfc8bafc9e7e2181d6ae..ecc5ca0bab06524a7d4a3acb6c64d6aa72309516 100644 (file)
@@ -23,7 +23,7 @@ Match.Name,                config_parse_ifname,           0,       offsetof(Netw
 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.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.VLAN,              config_parse_vlan,             0,       offsetof(Network, vlans)
 Network.DHCP,              config_parse_bool,             0,       offsetof(Network, dhcp)
 Network.Address,           config_parse_address,          0,       0
 Network.Gateway,           config_parse_gateway,          0,       0
 Network.DHCP,              config_parse_bool,             0,       offsetof(Network, dhcp)
 Network.Address,           config_parse_address,          0,       0
 Network.Gateway,           config_parse_gateway,          0,       0
@@ -41,4 +41,4 @@ DHCPv4.CriticalConnection, config_parse_bool,             0,       offsetof(Netw
 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)
 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)
+VLAN.Id,                   config_parse_uint64,           0,       offsetof(NetDev, vlanid)
index 6468f9cd3160d1409d828c34856a9ef8350c8bcc..5e763069f3622367e430a662c62a9cac45fc3f4f 100644 (file)
@@ -866,6 +866,8 @@ static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
 }
 
 static int link_enter_enslave(Link *link) {
 }
 
 static int link_enter_enslave(Link *link) {
+        NetDev *vlan;
+        Iterator i;
         int r;
 
         assert(link);
         int r;
 
         assert(link);
@@ -874,7 +876,7 @@ static int link_enter_enslave(Link *link) {
 
         link->state = LINK_STATE_ENSLAVING;
 
 
         link->state = LINK_STATE_ENSLAVING;
 
-        if (!link->network->bridge && !link->network->bond && !link->network->vlan)
+        if (!link->network->bridge && !link->network->bond && !link->network->vlans)
                 return link_enslaved(link);
 
         if (link->network->bridge) {
                 return link_enslaved(link);
 
         if (link->network->bridge) {
@@ -898,20 +900,17 @@ static int link_enter_enslave(Link *link) {
                 link->enslaving ++;
         }
 
                 link->enslaving ++;
         }
 
-        if (link->network->vlan) {
+        HASHMAP_FOREACH(vlan, link->network->vlans, i) {
                 log_struct_link(LOG_DEBUG, link,
                                 "MESSAGE=%s: enslaving by '%s'",
                 log_struct_link(LOG_DEBUG, link,
                                 "MESSAGE=%s: enslaving by '%s'",
-                                link->ifname, link->network->vlan->name,
-                                NETDEV(link->network->vlan),
-                                NULL);
+                                link->ifname, vlan->name, NETDEV(vlan), NULL);
 
 
-                r = netdev_enslave(link->network->vlan, link, &enslave_handler);
+                r = netdev_enslave(vlan, link, &enslave_handler);
                 if (r < 0) {
                         log_struct_link(LOG_WARNING, link,
                                         "MESSAGE=%s: could not enslave by '%s': %s",
                 if (r < 0) {
                         log_struct_link(LOG_WARNING, link,
                                         "MESSAGE=%s: could not enslave by '%s': %s",
-                                        link->ifname, link->network->vlan->name,
-                                        strerror(-r), NETDEV(link->network->vlan),
-                                        NULL);
+                                        link->ifname, vlan->name, strerror(-r),
+                                        NETDEV(vlan), NULL);
                         link_enter_failed(link);
                         return r;
                 }
                         link_enter_failed(link);
                         return r;
                 }
index 76f1deae58ad8c902d76cd01f72b2d15c97d7db2..c9b9b2bfd0d8266a5f21fabd1095a31cf35d69ea 100644 (file)
@@ -26,6 +26,8 @@
 #include "conf-parser.h"
 #include "list.h"
 
 #include "conf-parser.h"
 #include "list.h"
 
+#define VLANID_MAX 4094
+
 static const char* const netdev_kind_table[] = {
         [NETDEV_KIND_BRIDGE] = "bridge",
         [NETDEV_KIND_BOND] = "bond",
 static const char* const netdev_kind_table[] = {
         [NETDEV_KIND_BRIDGE] = "bridge",
         [NETDEV_KIND_BOND] = "bond",
@@ -161,7 +163,7 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
         int r;
 
         assert(netdev);
         int r;
 
         assert(netdev);
-        assert(!(netdev->kind == NETDEV_KIND_VLAN) || (link && callback && netdev->vlanid >= 0));
+        assert(!(netdev->kind == NETDEV_KIND_VLAN) || (link && callback && netdev->vlanid <= VLANID_MAX));
         assert(netdev->name);
         assert(netdev->manager);
         assert(netdev->manager->rtnl);
         assert(netdev->name);
         assert(netdev->manager);
         assert(netdev->manager->rtnl);
@@ -214,7 +216,7 @@ static int netdev_create(NetDev *netdev, Link *link, sd_rtnl_message_handler_t c
                 return r;
         }
 
                 return r;
         }
 
-        if (netdev->vlanid >= 0) {
+        if (netdev->vlanid <= VLANID_MAX) {
                 r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
                 if (r < 0) {
                         log_error_netdev(netdev,
                 r = sd_rtnl_message_open_container(req, IFLA_INFO_DATA);
                 if (r < 0) {
                         log_error_netdev(netdev,
@@ -329,7 +331,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
         netdev->manager = manager;
         netdev->state = _NETDEV_STATE_INVALID;
         netdev->kind = _NETDEV_KIND_INVALID;
         netdev->manager = manager;
         netdev->state = _NETDEV_STATE_INVALID;
         netdev->kind = _NETDEV_KIND_INVALID;
-        netdev->vlanid = -1;
+        netdev->vlanid = VLANID_MAX + 1;
 
         r = config_parse(NULL, filename, file, "NetDev\0VLAN\0", config_item_perf_lookup,
                         (void*) network_gperf_lookup, false, false, netdev);
 
         r = config_parse(NULL, filename, file, "NetDev\0VLAN\0", config_item_perf_lookup,
                         (void*) network_gperf_lookup, false, false, netdev);
@@ -348,8 +350,8 @@ static int netdev_load_one(Manager *manager, const char *filename) {
                 return 0;
         }
 
                 return 0;
         }
 
-        if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid < 0) {
-                log_warning("VLAN without Id configured in %s. Ignoring", filename);
+        if (netdev->kind == NETDEV_KIND_VLAN && netdev->vlanid > VLANID_MAX) {
+                log_warning("VLAN without valid Id configured in %s. Ignoring", filename);
                 return 0;
         }
 
                 return 0;
         }
 
index 5d930235b3286b20a9049a78486875979524496b..48131c1f090c1ea7af793a6c158d347771fb4aba 100644 (file)
@@ -53,6 +53,10 @@ static int network_load_one(Manager *manager, const char *filename) {
         LIST_HEAD_INIT(network->static_addresses);
         LIST_HEAD_INIT(network->static_routes);
 
         LIST_HEAD_INIT(network->static_addresses);
         LIST_HEAD_INIT(network->static_routes);
 
+        network->vlans = hashmap_new(uint64_hash_func, uint64_compare_func);
+        if (!network->vlans)
+                return log_oom();
+
         network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
         if (!network->addresses_by_section)
                 return log_oom();
         network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
         if (!network->addresses_by_section)
                 return log_oom();
@@ -144,6 +148,8 @@ void network_free(Network *network) {
 
         address_free(network->dns);
 
 
         address_free(network->dns);
 
+        hashmap_free(network->vlans);
+
         while ((route = network->static_routes))
                 route_free(route);
 
         while ((route = network->static_routes))
                 route_free(route);
 
@@ -312,7 +318,12 @@ int config_parse_vlan(const char *unit,
                 return 0;
         }
 
                 return 0;
         }
 
-        network->vlan = netdev;
+        r = hashmap_put(network->vlans, &netdev->vlanid, netdev);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Can not add VLAN to network: %s", rvalue);
+                return 0;
+        }
 
         return 0;
 }
 
         return 0;
 }
index 184f631ecfa39a564103d2e88aa20b1552146f14..726cd836996fcc7c1072a6543f20fe4e9b65fa0d 100644 (file)
@@ -75,7 +75,7 @@ struct NetDev {
         char *name;
         NetDevKind kind;
 
         char *name;
         NetDevKind kind;
 
-        int vlanid;
+        uint64_t vlanid;
 
         int ifindex;
         NetDevState state;
 
         int ifindex;
         NetDevState state;
@@ -97,7 +97,7 @@ struct Network {
         char *description;
         NetDev *bridge;
         NetDev *bond;
         char *description;
         NetDev *bridge;
         NetDev *bond;
-        NetDev *vlan;
+        Hashmap *vlans;
         bool dhcp;
         bool dhcp_dns;
         bool dhcp_mtu;
         bool dhcp;
         bool dhcp_dns;
         bool dhcp_mtu;