diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | man/systemd.netdev.xml | 115 | ||||
-rw-r--r-- | src/network/networkd-netdev-gperf.gperf | 10 | ||||
-rw-r--r-- | src/network/networkd-netdev.c | 32 | ||||
-rw-r--r-- | src/network/networkd-tuntap.c | 157 | ||||
-rw-r--r-- | src/network/networkd.h | 9 |
6 files changed, 317 insertions, 7 deletions
diff --git a/Makefile.am b/Makefile.am index cc3b7fd5db..672e93f16e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4535,6 +4535,7 @@ libsystemd_networkd_core_la_SOURCES = \ src/network/networkd-vlan.c \ src/network/networkd-macvlan.c \ src/network/networkd-dummy.c \ + src/network/networkd-tuntap.c \ src/network/networkd-network.c \ src/network/networkd-address.c \ src/network/networkd-route.c \ diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 5d033e77d3..a57ba7ad8c 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -340,6 +340,112 @@ </variablelist> </refsect1> <refsect1> + <title>[TUN] Section Options</title> + + <para>The <literal>[TUN]</literal> section only applies for netdevs of kind + <literal>tun</literal>, and accepts the following keys:</para> + + <variablelist class='network-directives'> + <varlistentry> + <term><varname>OneQueue=</varname></term> + <listitem><para>Takes a boolean argument. Configures whether + to enable disable one queue . it determines whether all packets + queue at the device (enabled), or a fixed number queue at the device and + the rest at the "qdisc". Defaults to <literal>no</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>MultiQueue=</varname></term> + <listitem><para>Takes a boolean argument. Configures whether the + to disable or disable . Linux supports multiqueue tuntap which can + uses multiple file descriptors (queues) to parallelize + packets sending or receiving. The device allocation is the same as before, + and if user wants to create multiple queues. Defaults to + <literal>no</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>PacketInfo=</varname></term> + <listitem><para>Takes a boolean argument. Configures whether the + to enable or disable . PacketInfo tells the kernel to not provide packet + information. The purpose of PacketInfo is to tell the kernel that packets + will be "pure" IP packets, with no added bytes. Otherwise (if PacketInfo is unset), + 4 extra bytes are added to the beginning of the packet (2 flag bytes and 2 protocol bytes). + Defaults to <literal>no</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>User=</varname></term> + <listitem><para>User to be allowed to access this device. Give ownership to unprivileged users, + so that /dev/net/tun device to be usable by this user. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>Group=</varname></term> + <listitem><para>Group to be allowed to access this device. Give ownership to unprivileged group, + so that /dev/net/tun device to be usable by this group.</para> + </listitem> + </varlistentry> + + </variablelist> + + </refsect1> + + <refsect1> + <title>[TAP] Section Options</title> + + <para>The <literal>[TAP]</literal> section only applies for netdevs of kind + <literal>tap</literal>, and accepts the following keys:</para> + </refsect1> + + <variablelist class='network-directives'> + <varlistentry> + <term><varname>OneQueue=</varname></term> + <listitem><para>Takes a boolean argument. Configures whether + to enable disable one queue . it determines whether all packets + queue at the device (enabled), or a fixed number queue at the device and + the rest at the "qdisc". Defaults to <literal>no</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>MultiQueue=</varname></term> + <listitem><para>Takes a boolean argument. Configures whether the + to disable or disable . From version 3.8, Linux supports multiqueue + tuntap which can uses multiple file descriptors (queues) to parallelize + packets sending or receiving. The device allocation is the same as before, + and if user wants to create multiple queues. Defaults to + <literal>no</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>PacketInfo=</varname></term> + <listitem><para>Takes a boolean argument. Configures whether the + to enable or disable . PacketInfo tells the kernel to not provide packet + information. The purpose of PacketInfo is to tell the kernel that packets + will be "pure" IP packets, with no added bytes. Otherwise (if PacketInfo is unset), + 4 extra bytes are added to the beginning of the packet (2 flag bytes and 2 protocol bytes). + Defaults to <literal>no</literal>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>User=</varname></term> + <listitem><para>User to be allowed to access this device. Give ownership to unprivileged users, + so that /dev/net/tun device to be usable by this user. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>Group=</varname></term> + <listitem><para>Group to be allowed to access this device. Give ownership to unprivileged group, + so that /dev/net/tun device to be usable by this group.</para> + </listitem> + </varlistentry> + + </variablelist> + + + <refsect1> <title>Example</title> <example> <title>/etc/systemd/network/bridge.netdev</title> @@ -374,6 +480,15 @@ Local=192.168.223.238 Remote=192.169.224.239 TTL=64</programlisting> </example> + <example> + <title>/etc/systemd/network/tap.netdev</title> + <programlisting>[NetDev] +Name=tap-test +Kind=tap + +[Tap] +MultiQueue=true +PacketInfo=true</programlisting> </example> <example> <title>/etc/systemd/network/sit.netdev</title> diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 9125e1db4e..5955f5195e 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -38,3 +38,13 @@ VXLAN.Group, config_parse_tunnel_address, 0, VXLAN.TOS, config_parse_unsigned, 0, offsetof(NetDev, tos) VXLAN.TTL, config_parse_unsigned, 0, offsetof(NetDev, ttl) VXLAN.MacLearning, config_parse_bool, 0, offsetof(NetDev, learning) +Tun.OneQueue, config_parse_bool, 0, offsetof(NetDev, one_queue) +Tun.MultiQueue, config_parse_bool, 0, offsetof(NetDev, multi_queue) +Tun.PacketInfo, config_parse_bool, 0, offsetof(NetDev, packet_info) +Tun.User, config_parse_string, 0, offsetof(NetDev, user_name) +Tun.Group, config_parse_string, 0, offsetof(NetDev, group_name) +Tap.OneQueue, config_parse_bool, 0, offsetof(NetDev, one_queue) +Tap.MultiQueue, config_parse_bool, 0, offsetof(NetDev, multi_queue) +Tap.PacketInfo, config_parse_bool, 0, offsetof(NetDev, packet_info) +Tap.User, config_parse_string, 0, offsetof(NetDev, user_name) +Tap.Group, config_parse_string, 0, offsetof(NetDev, group_name) diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index eaa8bede7a..cc85e5348b 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -41,6 +41,8 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { [NETDEV_KIND_VETH] = "veth", [NETDEV_KIND_VTI] = "vti", [NETDEV_KIND_DUMMY] = "dummy", + [NETDEV_KIND_TUN] = "tun", + [NETDEV_KIND_TAP] = "tap", }; DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); @@ -86,6 +88,8 @@ static void netdev_free(NetDev *netdev) { free(netdev->ifname_peer); free(netdev->mac); free(netdev->mac_peer); + free(netdev->user_name); + free(netdev->group_name); condition_free_list(netdev->match_host); condition_free_list(netdev->match_virt); @@ -484,15 +488,21 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) { return r; } - kind = netdev_kind_to_string(netdev->kind); - if (!kind) { - log_error_netdev(netdev, "Could not get kind"); - netdev_enter_failed(netdev); - return -EINVAL; + if (netdev->kind == NETDEV_KIND_TAP) + /* the kernel does not distinguish between tun and tap */ + kind = "tun"; + else { + kind = netdev_kind_to_string(netdev->kind); + if (!kind) { + log_error_netdev(netdev, "Could not get kind"); + netdev_enter_failed(netdev); + return -EINVAL; + } } if (!streq(kind, received_kind)) { - log_error_netdev(netdev, "Received newlink with wrong KIND %s, " + log_error_netdev(netdev, + "Received newlink with wrong KIND %s, " "expected %s", received_kind, kind); netdev_enter_failed(netdev); return r; @@ -589,7 +599,7 @@ static int netdev_load_one(Manager *manager, const char *filename) { netdev->learning = true; r = config_parse(NULL, filename, file, - "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0", + "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0Tun\0Tap\0", config_item_perf_lookup, (void*) network_netdev_gperf_lookup, false, false, netdev); if (r < 0) { @@ -695,6 +705,14 @@ static int netdev_load_one(Manager *manager, const char *filename) { if (r < 0) return r; break; + + case NETDEV_KIND_TUN: + case NETDEV_KIND_TAP: + r = netdev_create_tuntap(netdev); + if (r < 0) + return r; + break; + default: break; } diff --git a/src/network/networkd-tuntap.c b/src/network/networkd-tuntap.c new file mode 100644 index 0000000000..19dc2ad252 --- /dev/null +++ b/src/network/networkd-tuntap.c @@ -0,0 +1,157 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Susant Sahani <susant@redhat.com> + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/ioctl.h> +#include <net/if.h> +#include <linux/if_tun.h> + +#include "networkd.h" + +#define TUN_DEV "/dev/net/tun" + + +static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) { + + assert(netdev); + assert(ifr); + + memset(ifr, 0, sizeof(*ifr)); + + if (netdev->kind != NETDEV_KIND_TAP) + ifr->ifr_flags |= IFF_TUN; + else + ifr->ifr_flags |= IFF_TAP; + + if (netdev->packet_info) + ifr->ifr_flags &= ~IFF_NO_PI; + else + ifr->ifr_flags |= IFF_NO_PI; + + if (netdev->one_queue) + ifr->ifr_flags |= IFF_ONE_QUEUE; + + if (netdev->multi_queue) + ifr->ifr_flags |= IFF_MULTI_QUEUE; + + strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1); + + return 0; +} + +static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) { + _cleanup_close_ int fd; + const char *user; + const char *group; + uid_t uid; + gid_t gid; + int r = 0; + + fd = open(TUN_DEV, O_RDWR); + if (fd < 0) { + log_error_netdev(netdev, + "Failed to open tun dev: %s", + strerror(-r)); + return r; + } + + r = ioctl(fd, TUNSETIFF, ifr); + if (r < 0) { + log_error_netdev(netdev, + "TUNSETIFF failed on tun dev: %s", + strerror(-r)); + return r; + } + + if(netdev->user_name) { + + user = netdev->user_name; + + r = get_user_creds(&user, &uid, NULL, NULL, NULL); + if (r < 0) { + log_error("Cannot resolve user name %s: %s", + netdev->user_name, strerror(-r)); + return 0; + } + + r = ioctl(fd, TUNSETOWNER, uid); + if ( r < 0) { + log_error_netdev(netdev, + "TUNSETOWNER failed on tun dev: %s", + strerror(-r)); + } + } + + if(netdev->group_name) { + + group = netdev->group_name; + + r = get_group_creds(&group, &gid); + if (r < 0) { + log_error("Cannot resolve group name %s: %s", + netdev->group_name, strerror(-r)); + return 0; + } + + r = ioctl(fd, TUNSETGROUP, gid); + if( r < 0) { + log_error_netdev(netdev, + "TUNSETGROUP failed on tun dev: %s", + strerror(-r)); + return r; + } + + } + + r = ioctl(fd, TUNSETPERSIST, 1); + if (r < 0) { + log_error_netdev(netdev, + "TUNSETPERSIST failed on tun dev: %s", + strerror(-r)); + return r; + } + + return r; +} + +int netdev_create_tuntap(NetDev *netdev) { + struct ifreq ifr; + int r; + + assert(netdev); + assert(netdev->ifname); + + switch(netdev->kind) { + case NETDEV_KIND_TUN: + case NETDEV_KIND_TAP: + break; + default: + return -ENOTSUP; + } + + r = netdev_fill_tuntap_message(netdev, &ifr); + if(r < 0) + return r; + + log_debug_netdev(netdev, "Creating tuntap netdev: %s", + netdev_kind_to_string(netdev->kind)); + + return netdev_tuntap_add(netdev, &ifr); +} diff --git a/src/network/networkd.h b/src/network/networkd.h index 0ba9ee5880..67ca41b8a4 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -82,6 +82,8 @@ typedef enum NetDevKind { NETDEV_KIND_VETH, NETDEV_KIND_VTI, NETDEV_KIND_DUMMY, + NETDEV_KIND_TUN, + NETDEV_KIND_TAP, _NETDEV_KIND_MAX, _NETDEV_KIND_INVALID = -1 } NetDevKind; @@ -110,6 +112,8 @@ struct NetDev { char *description; char *ifname; char *ifname_peer; + char *user_name; + char *group_name; size_t mtu; struct ether_addr *mac; struct ether_addr *mac_peer; @@ -124,6 +128,10 @@ struct NetDev { bool tunnel_pmtudisc; bool learning; + bool one_queue; + bool multi_queue; + bool packet_info; + unsigned ttl; unsigned tos; struct in_addr local; @@ -359,6 +367,7 @@ int netdev_create_vxlan(NetDev *netdev, Link *link, sd_rtnl_message_handler_t ca int netdev_create_vlan(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback); int netdev_create_macvlan(NetDev *netdev, Link *link, sd_rtnl_message_handler_t callback); int netdev_create_dummy(NetDev *netdev, sd_rtnl_message_handler_t callback); +int netdev_create_tuntap(NetDev *netdev); const char *netdev_kind_to_string(NetDevKind d) _const_; NetDevKind netdev_kind_from_string(const char *d) _pure_; |