2 This file is part of systemd.
4 Copyright 2014 Susant Sahani <susant@redhat.com>
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.
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.
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/>.
21 #include <linux/if_tun.h>
23 #include <netinet/if_ether.h>
24 #include <sys/ioctl.h>
26 #include <sys/types.h>
28 #include "alloc-util.h"
30 #include "networkd-netdev-tuntap.h"
31 #include "user-util.h"
33 #define TUN_DEV "/dev/net/tun"
35 static int netdev_fill_tuntap_message(NetDev
*netdev
, struct ifreq
*ifr
) {
39 assert(netdev
->ifname
);
42 if (netdev
->kind
== NETDEV_KIND_TAP
) {
44 ifr
->ifr_flags
|= IFF_TAP
;
47 ifr
->ifr_flags
|= IFF_TUN
;
51 ifr
->ifr_flags
|= IFF_NO_PI
;
54 ifr
->ifr_flags
|= IFF_ONE_QUEUE
;
57 ifr
->ifr_flags
|= IFF_MULTI_QUEUE
;
60 ifr
->ifr_flags
|= IFF_VNET_HDR
;
62 strncpy(ifr
->ifr_name
, netdev
->ifname
, IFNAMSIZ
-1);
67 static int netdev_tuntap_add(NetDev
*netdev
, struct ifreq
*ifr
) {
68 _cleanup_close_
int fd
;
79 fd
= open(TUN_DEV
, O_RDWR
);
81 return log_netdev_error_errno(netdev
, -errno
, "Failed to open tun dev: %m");
83 r
= ioctl(fd
, TUNSETIFF
, ifr
);
85 return log_netdev_error_errno(netdev
, -errno
, "TUNSETIFF failed on tun dev: %m");
87 if (netdev
->kind
== NETDEV_KIND_TAP
)
98 r
= get_user_creds(&user
, &uid
, NULL
, NULL
, NULL
);
100 return log_netdev_error_errno(netdev
, r
, "Cannot resolve user name %s: %m", t
->user_name
);
102 r
= ioctl(fd
, TUNSETOWNER
, uid
);
104 return log_netdev_error_errno(netdev
, -errno
, "TUNSETOWNER failed on tun dev: %m");
109 group
= t
->group_name
;
111 r
= get_group_creds(&group
, &gid
);
113 return log_netdev_error_errno(netdev
, r
, "Cannot resolve group name %s: %m", t
->group_name
);
115 r
= ioctl(fd
, TUNSETGROUP
, gid
);
117 return log_netdev_error_errno(netdev
, -errno
, "TUNSETGROUP failed on tun dev: %m");
121 r
= ioctl(fd
, TUNSETPERSIST
, 1);
123 return log_netdev_error_errno(netdev
, -errno
, "TUNSETPERSIST failed on tun dev: %m");
128 static int netdev_create_tuntap(NetDev
*netdev
) {
129 struct ifreq ifr
= {};
132 r
= netdev_fill_tuntap_message(netdev
, &ifr
);
136 return netdev_tuntap_add(netdev
, &ifr
);
139 static void tuntap_done(NetDev
*netdev
) {
144 if (netdev
->kind
== NETDEV_KIND_TUN
)
151 t
->user_name
= mfree(t
->user_name
);
152 t
->group_name
= mfree(t
->group_name
);
155 static int tuntap_verify(NetDev
*netdev
, const char *filename
) {
159 log_netdev_warning(netdev
, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev
->kind
));
162 log_netdev_warning(netdev
, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev
->kind
));
167 const NetDevVTable tun_vtable
= {
168 .object_size
= sizeof(TunTap
),
169 .sections
= "Match\0NetDev\0Tun\0",
170 .config_verify
= tuntap_verify
,
172 .create
= netdev_create_tuntap
,
173 .create_type
= NETDEV_CREATE_INDEPENDENT
,
176 const NetDevVTable tap_vtable
= {
177 .object_size
= sizeof(TunTap
),
178 .sections
= "Match\0NetDev\0Tap\0",
179 .config_verify
= tuntap_verify
,
181 .create
= netdev_create_tuntap
,
182 .create_type
= NETDEV_CREATE_INDEPENDENT
,