]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/netdev/tuntap.c
Merge pull request #7388 from keszybz/doc-tweak
[thirdparty/systemd.git] / src / network / netdev / tuntap.c
CommitLineData
30ae9dfd
SS
1/***
2 This file is part of systemd.
3
4 Copyright 2014 Susant Sahani <susant@redhat.com>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
634f0f98 20#include <fcntl.h>
30ae9dfd 21#include <linux/if_tun.h>
634f0f98 22#include <net/if.h>
e306723e 23#include <netinet/if_ether.h>
634f0f98
ZJS
24#include <sys/ioctl.h>
25#include <sys/stat.h>
26#include <sys/types.h>
30ae9dfd 27
b5efdb8a 28#include "alloc-util.h"
3ffd4af2 29#include "fd-util.h"
441e9ae4 30#include "netdev/tuntap.h"
b1d4f8e1 31#include "user-util.h"
30ae9dfd
SS
32
33#define TUN_DEV "/dev/net/tun"
34
30ae9dfd 35static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
aa9f1140 36 TunTap *t;
30ae9dfd
SS
37
38 assert(netdev);
aa9f1140 39 assert(netdev->ifname);
30ae9dfd
SS
40 assert(ifr);
41
aa9f1140
TG
42 if (netdev->kind == NETDEV_KIND_TAP) {
43 t = TAP(netdev);
30ae9dfd 44 ifr->ifr_flags |= IFF_TAP;
aa9f1140
TG
45 } else {
46 t = TUN(netdev);
63dadd90 47 ifr->ifr_flags |= IFF_TUN;
aa9f1140 48 }
63dadd90 49
aa9f1140 50 if (!t->packet_info)
30ae9dfd
SS
51 ifr->ifr_flags |= IFF_NO_PI;
52
aa9f1140 53 if (t->one_queue)
30ae9dfd
SS
54 ifr->ifr_flags |= IFF_ONE_QUEUE;
55
aa9f1140 56 if (t->multi_queue)
30ae9dfd
SS
57 ifr->ifr_flags |= IFF_MULTI_QUEUE;
58
f5f07dbf
SS
59 if (t->vnet_hdr)
60 ifr->ifr_flags |= IFF_VNET_HDR;
61
30ae9dfd
SS
62 strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
63
64 return 0;
65}
66
67static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
68 _cleanup_close_ int fd;
aa9f1140 69 TunTap *t = NULL;
30ae9dfd
SS
70 const char *user;
71 const char *group;
72 uid_t uid;
73 gid_t gid;
6f44acfb 74 int r;
30ae9dfd 75
aa9f1140
TG
76 assert(netdev);
77 assert(ifr);
78
30ae9dfd 79 fd = open(TUN_DEV, O_RDWR);
ce67afb0
SS
80 if (fd < 0)
81 return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
30ae9dfd
SS
82
83 r = ioctl(fd, TUNSETIFF, ifr);
ce67afb0
SS
84 if (r < 0)
85 return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
30ae9dfd 86
aa9f1140
TG
87 if (netdev->kind == NETDEV_KIND_TAP)
88 t = TAP(netdev);
89 else
90 t = TUN(netdev);
91
92 assert(t);
30ae9dfd 93
9ed794a3 94 if (t->user_name) {
aa9f1140
TG
95
96 user = t->user_name;
30ae9dfd
SS
97
98 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
ce67afb0
SS
99 if (r < 0)
100 return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
30ae9dfd
SS
101
102 r = ioctl(fd, TUNSETOWNER, uid);
ce67afb0
SS
103 if (r < 0)
104 return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
30ae9dfd
SS
105 }
106
98b32556 107 if (t->group_name) {
30ae9dfd 108
aa9f1140 109 group = t->group_name;
30ae9dfd
SS
110
111 r = get_group_creds(&group, &gid);
ce67afb0
SS
112 if (r < 0)
113 return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
30ae9dfd
SS
114
115 r = ioctl(fd, TUNSETGROUP, gid);
ce67afb0
SS
116 if (r < 0)
117 return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
30ae9dfd
SS
118
119 }
120
121 r = ioctl(fd, TUNSETPERSIST, 1);
ce67afb0
SS
122 if (r < 0)
123 return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
30ae9dfd 124
6f44acfb 125 return 0;
30ae9dfd
SS
126}
127
3be1d7e0 128static int netdev_create_tuntap(NetDev *netdev) {
aa9f1140 129 struct ifreq ifr = {};
30ae9dfd
SS
130 int r;
131
30ae9dfd 132 r = netdev_fill_tuntap_message(netdev, &ifr);
9ed794a3 133 if (r < 0)
30ae9dfd
SS
134 return r;
135
30ae9dfd
SS
136 return netdev_tuntap_add(netdev, &ifr);
137}
3be1d7e0 138
aa9f1140
TG
139static void tuntap_done(NetDev *netdev) {
140 TunTap *t = NULL;
141
142 assert(netdev);
143
144 if (netdev->kind == NETDEV_KIND_TUN)
145 t = TUN(netdev);
146 else
147 t = TAP(netdev);
148
149 assert(t);
150
a1e58e8e
LP
151 t->user_name = mfree(t->user_name);
152 t->group_name = mfree(t->group_name);
aa9f1140
TG
153}
154
e0fbf1fc 155static int tuntap_verify(NetDev *netdev, const char *filename) {
e0fbf1fc
TG
156 assert(netdev);
157
98b32556
LP
158 if (netdev->mtu)
159 log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc 160
98b32556
LP
161 if (netdev->mac)
162 log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc
TG
163
164 return 0;
165}
166
3be1d7e0 167const NetDevVTable tun_vtable = {
aa9f1140
TG
168 .object_size = sizeof(TunTap),
169 .sections = "Match\0NetDev\0Tun\0",
e0fbf1fc 170 .config_verify = tuntap_verify,
aa9f1140 171 .done = tuntap_done,
3be1d7e0 172 .create = netdev_create_tuntap,
aa9f1140 173 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0
TG
174};
175
176const NetDevVTable tap_vtable = {
aa9f1140
TG
177 .object_size = sizeof(TunTap),
178 .sections = "Match\0NetDev\0Tap\0",
e0fbf1fc 179 .config_verify = tuntap_verify,
aa9f1140 180 .done = tuntap_done,
3be1d7e0 181 .create = netdev_create_tuntap,
aa9f1140 182 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0 183};