networkd: Introduce tun/tap device

This patch introduces TUN/TAP device creation support
to networkd.

Example conf to create a tap device:

file: tap.netdev
------------------
[NetDev]
Name=tap-test
Kind=tap

[Tap]
OneQueue=true
MultiQueue=true
PacketInfo=true
User=sus
Group=sus
------------------

Test:
1. output of ip link
tap-test: tap pi one_queue UNKNOWN_FLAGS:900 user 1000 group 1000

id:
uid=1000(sus) gid=10(wheel) groups=10(wheel),1000(sus)
context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Modifications:

Added:
1. file networkd-tuntap.c
3. netdev kind NETDEV_KIND_TUN and NETDEV_KIND_TAP
2. Tun and Tap Sections and config params to parse
   conf and gperf conf parameters

[tomegun: tweak the 'kind' checking for received ifindex]
This commit is contained in:
Susant Sahani
2014-07-03 11:00:02 +02:00
committed by Tom Gundersen
parent 866ee36822
commit 30ae9dfda3
6 changed files with 317 additions and 7 deletions
+10
View File
@@ -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)
+25 -7
View File
@@ -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;
}
+157
View File
@@ -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);
}
+9
View File
@@ -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_;