]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-netdev-tuntap.c
Merge pull request #2719 from evverx/add-test-to-makefile
[thirdparty/systemd.git] / src / network / networkd-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
30ae9dfd 20#include <net/if.h>
cf0fbc49 21#include <sys/ioctl.h>
30ae9dfd 22#include <linux/if_tun.h>
e306723e 23#include <netinet/if_ether.h>
30ae9dfd 24
b5efdb8a 25#include "alloc-util.h"
3ffd4af2 26#include "fd-util.h"
b1d4f8e1
LP
27#include "networkd-netdev-tuntap.h"
28#include "user-util.h"
30ae9dfd
SS
29
30#define TUN_DEV "/dev/net/tun"
31
30ae9dfd 32static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) {
aa9f1140 33 TunTap *t;
30ae9dfd
SS
34
35 assert(netdev);
aa9f1140 36 assert(netdev->ifname);
30ae9dfd
SS
37 assert(ifr);
38
aa9f1140
TG
39 if (netdev->kind == NETDEV_KIND_TAP) {
40 t = TAP(netdev);
30ae9dfd 41 ifr->ifr_flags |= IFF_TAP;
aa9f1140
TG
42 } else {
43 t = TUN(netdev);
63dadd90 44 ifr->ifr_flags |= IFF_TUN;
aa9f1140 45 }
63dadd90 46
aa9f1140 47 if (!t->packet_info)
30ae9dfd
SS
48 ifr->ifr_flags |= IFF_NO_PI;
49
aa9f1140 50 if (t->one_queue)
30ae9dfd
SS
51 ifr->ifr_flags |= IFF_ONE_QUEUE;
52
aa9f1140 53 if (t->multi_queue)
30ae9dfd
SS
54 ifr->ifr_flags |= IFF_MULTI_QUEUE;
55
f5f07dbf
SS
56 if (t->vnet_hdr)
57 ifr->ifr_flags |= IFF_VNET_HDR;
58
30ae9dfd
SS
59 strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1);
60
61 return 0;
62}
63
64static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
65 _cleanup_close_ int fd;
aa9f1140 66 TunTap *t = NULL;
30ae9dfd
SS
67 const char *user;
68 const char *group;
69 uid_t uid;
70 gid_t gid;
6f44acfb 71 int r;
30ae9dfd 72
aa9f1140
TG
73 assert(netdev);
74 assert(ifr);
75
30ae9dfd 76 fd = open(TUN_DEV, O_RDWR);
ce67afb0
SS
77 if (fd < 0)
78 return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
30ae9dfd
SS
79
80 r = ioctl(fd, TUNSETIFF, ifr);
ce67afb0
SS
81 if (r < 0)
82 return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m");
30ae9dfd 83
aa9f1140
TG
84 if (netdev->kind == NETDEV_KIND_TAP)
85 t = TAP(netdev);
86 else
87 t = TUN(netdev);
88
89 assert(t);
30ae9dfd 90
9ed794a3 91 if (t->user_name) {
aa9f1140
TG
92
93 user = t->user_name;
30ae9dfd
SS
94
95 r = get_user_creds(&user, &uid, NULL, NULL, NULL);
ce67afb0
SS
96 if (r < 0)
97 return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
30ae9dfd
SS
98
99 r = ioctl(fd, TUNSETOWNER, uid);
ce67afb0
SS
100 if (r < 0)
101 return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m");
30ae9dfd
SS
102 }
103
98b32556 104 if (t->group_name) {
30ae9dfd 105
aa9f1140 106 group = t->group_name;
30ae9dfd
SS
107
108 r = get_group_creds(&group, &gid);
ce67afb0
SS
109 if (r < 0)
110 return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
30ae9dfd
SS
111
112 r = ioctl(fd, TUNSETGROUP, gid);
ce67afb0
SS
113 if (r < 0)
114 return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m");
30ae9dfd
SS
115
116 }
117
118 r = ioctl(fd, TUNSETPERSIST, 1);
ce67afb0
SS
119 if (r < 0)
120 return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m");
30ae9dfd 121
6f44acfb 122 return 0;
30ae9dfd
SS
123}
124
3be1d7e0 125static int netdev_create_tuntap(NetDev *netdev) {
aa9f1140 126 struct ifreq ifr = {};
30ae9dfd
SS
127 int r;
128
30ae9dfd 129 r = netdev_fill_tuntap_message(netdev, &ifr);
9ed794a3 130 if (r < 0)
30ae9dfd
SS
131 return r;
132
30ae9dfd
SS
133 return netdev_tuntap_add(netdev, &ifr);
134}
3be1d7e0 135
aa9f1140
TG
136static void tuntap_done(NetDev *netdev) {
137 TunTap *t = NULL;
138
139 assert(netdev);
140
141 if (netdev->kind == NETDEV_KIND_TUN)
142 t = TUN(netdev);
143 else
144 t = TAP(netdev);
145
146 assert(t);
147
a1e58e8e
LP
148 t->user_name = mfree(t->user_name);
149 t->group_name = mfree(t->group_name);
aa9f1140
TG
150}
151
e0fbf1fc 152static int tuntap_verify(NetDev *netdev, const char *filename) {
e0fbf1fc
TG
153 assert(netdev);
154
98b32556
LP
155 if (netdev->mtu)
156 log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc 157
98b32556
LP
158 if (netdev->mac)
159 log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind));
e0fbf1fc
TG
160
161 return 0;
162}
163
3be1d7e0 164const NetDevVTable tun_vtable = {
aa9f1140
TG
165 .object_size = sizeof(TunTap),
166 .sections = "Match\0NetDev\0Tun\0",
e0fbf1fc 167 .config_verify = tuntap_verify,
aa9f1140 168 .done = tuntap_done,
3be1d7e0 169 .create = netdev_create_tuntap,
aa9f1140 170 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0
TG
171};
172
173const NetDevVTable tap_vtable = {
aa9f1140
TG
174 .object_size = sizeof(TunTap),
175 .sections = "Match\0NetDev\0Tap\0",
e0fbf1fc 176 .config_verify = tuntap_verify,
aa9f1140 177 .done = tuntap_done,
3be1d7e0 178 .create = netdev_create_tuntap,
aa9f1140 179 .create_type = NETDEV_CREATE_INDEPENDENT,
3be1d7e0 180};