[systemd-devel] [PATCH] networkd: Introduce tuntap device
Tom Gundersen
teg at jklm.no
Tue Jun 24 10:01:42 PDT 2014
Looks great, just minor comments below.
On Tue, Jun 24, 2014 at 6:25 PM, Susant Sahani <susant at redhat.com> wrote:
> This patch introduces tuntap support to networkd.
>
> Example conf
>
> file : tuntap.netdev
>
> [NetDev]
> Name=tuntap-test
> Kind=tuntap
>
> [TUNTAP]
Hm, maybe call this TunTap instead?
> Mode=tap
> OneQueue=true
> MultiQueue=true
> PacketInfo=true
>
> Added:
> 1. file networkd-tuntap.c
> 2. enum TunTapKind
> 3. NETDEV_KIND_TUNTAP
> 4. TUNTAP Section to parse conf and gperf conf parameters
>
> TODO:
> 1. Add user(uid) group(gid) parameters
Yeah, this would be great to have as well.
> ---
> Makefile.am | 1 +
> src/network/networkd-netdev-gperf.gperf | 4 ++
> src/network/networkd-netdev.c | 40 +++++++++---
> src/network/networkd-tuntap.c | 106 ++++++++++++++++++++++++++++++++
> src/network/networkd.h | 19 ++++++
> 5 files changed, 163 insertions(+), 7 deletions(-)
> create mode 100644 src/network/networkd-tuntap.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 37a164e..d9cba3b 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -4479,6 +4479,7 @@ libsystemd_networkd_core_la_SOURCES = \
> src/network/networkd-tunnel.c \
> src/network/networkd-veth.c \
> src/network/networkd-vxlan.c \
> + src/network/networkd-tuntap.c \
> src/network/networkd-network.c \
> src/network/networkd-address.c \
> src/network/networkd-route.c \
> diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
> index 9125e1d..d29e41d 100644
> --- a/src/network/networkd-netdev-gperf.gperf
> +++ b/src/network/networkd-netdev-gperf.gperf
> @@ -38,3 +38,7 @@ 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)
> +TUNTAP.Mode, config_parse_tuntap_kind, 0, offsetof(NetDev, tuntap_kind)
> +TUNTAP.OneQueue, config_parse_bool, 0, offsetof(NetDev, one_queue)
> +TUNTAP.MultiQueue, config_parse_bool, 0, offsetof(NetDev, multi_queue)
> +TUNTAP.PacketInfo, config_parse_bool, 0, offsetof(NetDev, packet_info)
> diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
> index dcf7596..41db707 100644
> --- a/src/network/networkd-netdev.c
> +++ b/src/network/networkd-netdev.c
> @@ -41,7 +41,8 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
> [NETDEV_KIND_GRE] = "gre",
> [NETDEV_KIND_SIT] = "sit",
> [NETDEV_KIND_VETH] = "veth",
> - [NETDEV_KIND_VTI] = "vti"
> + [NETDEV_KIND_VTI] = "vti",
> + [NETDEV_KIND_TUNTAP] = "tuntap"
> };
>
> DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
> @@ -57,6 +58,14 @@ static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = {
> DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode);
> DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode");
>
> +static const char* const tuntap_kind_table[_TUNTAP_KIND_MAX] = {
> + [TUNTAP_KIND_TAP] = "tap",
> + [TUNTAP_KIND_TUNNEL] = "tunnel",
> +};
> +
> +DEFINE_STRING_TABLE_LOOKUP(tuntap_kind, TunTapKind);
> +DEFINE_CONFIG_PARSE_ENUM(config_parse_tuntap_kind, tuntap_kind, TunTapKind, "Failed to parse tuntap kind");
> +
> static void netdev_cancel_callbacks(NetDev *netdev) {
> _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
> netdev_enslave_callback *callback;
> @@ -521,11 +530,13 @@ int netdev_set_ifindex(NetDev *netdev, sd_rtnl_message *message) {
> return -EINVAL;
> }
>
> - if (!streq(kind, received_kind)) {
> - log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
> - "expected %s", received_kind, kind);
> - netdev_enter_failed(netdev);
> - return r;
> + if (netdev->kind != NETDEV_KIND_TUNTAP) {
Probably better explain why tuntap needs special casing in a comment here.
> + if (!streq(kind, received_kind)) {
> + log_error_netdev(netdev, "Received newlink with wrong KIND %s, "
> + "expected %s", received_kind, kind);
> + netdev_enter_failed(netdev);
> + return r;
> + }
> }
>
> netdev->ifindex = ifindex;
> @@ -612,14 +623,16 @@ static int netdev_load_one(Manager *manager, const char *filename) {
> netdev->manager = manager;
> netdev->state = _NETDEV_STATE_INVALID;
> netdev->kind = _NETDEV_KIND_INVALID;
> + netdev->tuntap_kind = _TUNTAP_KIND_INVALID;
> netdev->macvlan_mode = _NETDEV_MACVLAN_MODE_INVALID;
> netdev->vlanid = VLANID_MAX + 1;
> netdev->vxlanid = VXLAN_VID_MAX + 1;
> netdev->tunnel_pmtudisc = true;
> netdev->learning = true;
> + netdev->packet_info = true;
>
> r = config_parse(NULL, filename, file,
> - "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0",
> + "Match\0NetDev\0VLAN\0MACVLAN\0VXLAN\0Tunnel\0Peer\0TUNTAP\0",
> config_item_perf_lookup, (void*) network_netdev_gperf_lookup,
> false, false, netdev);
> if (r < 0) {
> @@ -666,6 +679,12 @@ static int netdev_load_one(Manager *manager, const char *filename) {
> return 0;
> }
>
> + if (netdev->kind == NETDEV_KIND_TUNTAP &&
> + netdev->tuntap_kind == _TUNTAP_KIND_INVALID) {
> + log_warning("TunTap without Mode configured in %s. Ignoring", filename);
> + return 0;
> + }
> +
> netdev->filename = strdup(filename);
> if (!netdev->filename)
> return log_oom();
> @@ -719,6 +738,13 @@ static int netdev_load_one(Manager *manager, const char *filename) {
> if (r < 0)
> return r;
> break;
> +
> + case NETDEV_KIND_TUNTAP:
> + 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 0000000..f138b8a
> --- /dev/null
> +++ b/src/network/networkd-tuntap.c
> @@ -0,0 +1,106 @@
> +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
> +
> +/***
> + This file is part of systemd.
> +
> + Copyright 2014 Susant Sahani <susant at 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->tuntap_kind == TUNTAP_KIND_TAP)
> + ifr->ifr_flags |= IFF_TAP;
> + else
> + ifr->ifr_flags |= IFF_TUN;
> +
> + 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(struct ifreq *ifr)
> +{
> + int fd;
> + int r = 0;
> +
> + fd = open(TUN_DEV, O_RDWR);
> + if (fd < 0) {
> + r = -errno;
> + goto fail;
> + }
> +
> + r = ioctl(fd, TUNSETIFF, ifr);
> + if (r < 0) {
> + r = -errno;
> + goto fail;
> + }
> +
> + r = ioctl(fd, TUNSETPERSIST, 1);
> + if (r < 0) {
> + r = -errno;
> + goto fail;
> + }
> +
> + fail:
> + close(fd);
> +
> + return r;
> +}
> +
> +int netdev_create_tuntap(NetDev *netdev) {
> + int r;
> + struct ifreq ifr;
> +
> + assert(netdev);
> + assert(netdev->ifname);
> +
> + if(netdev->kind != NETDEV_KIND_TUNTAP)
> + 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(&ifr);
> +}
> diff --git a/src/network/networkd.h b/src/network/networkd.h
> index b7b1d90..ab1ca4e 100644
> --- a/src/network/networkd.h
> +++ b/src/network/networkd.h
> @@ -80,6 +80,7 @@ typedef enum NetDevKind {
> NETDEV_KIND_SIT,
> NETDEV_KIND_VETH,
> NETDEV_KIND_VTI,
> + NETDEV_KIND_TUNTAP,
> _NETDEV_KIND_MAX,
> _NETDEV_KIND_INVALID = -1
> } NetDevKind;
> @@ -93,6 +94,13 @@ typedef enum NetDevState {
> _NETDEV_STATE_INVALID = -1,
> } NetDevState;
>
> +typedef enum TunTapKind {
> + TUNTAP_KIND_TAP,
> + TUNTAP_KIND_TUNNEL,
> + _TUNTAP_KIND_MAX,
> + _TUNTAP_KIND_INVALID = -1
> +} TunTapKind;
> +
> struct NetDev {
> Manager *manager;
>
> @@ -112,6 +120,7 @@ struct NetDev {
> struct ether_addr *mac;
> struct ether_addr *mac_peer;
> NetDevKind kind;
> + TunTapKind tuntap_kind;
>
> uint64_t vlanid;
> uint64_t vxlanid;
> @@ -122,6 +131,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;
> @@ -342,6 +355,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_rtnl_message_handler_t cb);
> int netdev_create_tunnel(Link *link, sd_rtnl_message_handler_t callback);
> int netdev_create_veth(NetDev *netdev, sd_rtnl_message_handler_t callback);
> int netdev_create_vxlan(NetDev *netdev, Link *link, 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_;
> @@ -349,10 +363,15 @@ NetDevKind netdev_kind_from_string(const char *d) _pure_;
> const char *macvlan_mode_to_string(MacVlanMode d) _const_;
> MacVlanMode macvlan_mode_from_string(const char *d) _pure_;
>
> +const char *tuntap_kind_to_string(TunTapKind d) _const_;
> +TunTapKind tuntap_kind_from_string(const char *d) _pure_;
> +
> int config_parse_netdev_kind(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_macvlan_mode(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_tuntap_kind(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_netdev_gperf_lookup(const char *key, unsigned length);
>
> --
> 1.9.3
>
More information about the systemd-devel
mailing list