2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2002 Jeff Dike
7 * Based on the "tunctl" utility from Jeff Dike.
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 #include <sys/types.h>
25 #include <sys/ioctl.h>
26 #include <linux/if_tun.h>
29 #include <utils/linked_list.h>
33 typedef struct private_iface_t private_iface_t
;
35 struct private_iface_t
{
36 /** public interface */
38 /** device name in guest (eth0) */
40 /** device name at host (tap0) */
42 /** bridge this interface is attached to */
44 /** guest this interface is attached to */
46 /** mconsole for guest */
51 * bring an interface up or down (host side)
53 bool iface_control(char *name
, bool up
)
59 memset(&ifr
, 0, sizeof(struct ifreq
));
60 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
62 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
67 if (ioctl(s
, SIOCGIFFLAGS
, &ifr
) == 0)
71 ifr
.ifr_flags
|= IFF_UP
;
75 ifr
.ifr_flags
&= ~IFF_UP
;
77 if (ioctl(s
, SIOCSIFFLAGS
, &ifr
) == 0)
87 * Implementation of iface_t.get_guestif.
89 static char* get_guestif(private_iface_t
*this)
95 * Implementation of iface_t.get_hostif.
97 static char* get_hostif(private_iface_t
*this)
103 * Implementation of iface_t.add_address
105 static bool add_address(private_iface_t
*this, host_t
*addr
)
107 return (this->guest
->exec(this->guest
, NULL
, NULL
,
108 "exec ip addr add %H dev %s", addr
, this->guestif
) == 0);
112 * compile a list of the addresses of an interface
114 static void compile_address_list(linked_list_t
*list
, char *address
)
116 host_t
*host
= host_create_from_string(address
, 0);
119 list
->insert_last(list
, host
);
124 * delete the list of addresses
126 static void destroy_address_list(linked_list_t
*list
)
128 list
->destroy_offset(list
, offsetof(host_t
, destroy
));
132 * Implementation of iface_t.create_address_enumerator
134 static enumerator_t
* create_address_enumerator(private_iface_t
*this)
136 linked_list_t
*addresses
= linked_list_create();
137 this->guest
->exec_str(this->guest
, (void(*)(void*,char*))compile_address_list
,
139 "exec ip addr list dev %s scope global | "
140 "grep '^ \\+\\(inet6\\? \\)' | "
141 "awk -F '( +|/)' '{ print $3 }'", this->guestif
);
142 return enumerator_create_cleaner(addresses
->create_enumerator(addresses
),
143 (void(*)(void*))destroy_address_list
, addresses
);
147 * Implementation of iface_t.delete_address
149 static bool delete_address(private_iface_t
*this, host_t
*addr
)
151 return (this->guest
->exec(this->guest
, NULL
, NULL
,
152 "exec ip addr del %H dev %s", addr
, this->guestif
) == 0);
156 * Implementation of iface_t.set_bridge.
158 static void set_bridge(private_iface_t
*this, bridge_t
*bridge
)
160 if (this->bridge
== NULL
&& bridge
)
162 this->guest
->exec(this->guest
, NULL
, NULL
,
163 "exec ip link set %s up", this->guestif
);
165 else if (this->bridge
&& bridge
== NULL
)
167 this->guest
->exec(this->guest
, NULL
, NULL
,
168 "exec ip link set %s down", this->guestif
);
170 this->bridge
= bridge
;
174 * Implementation of iface_t.get_bridge
176 static bridge_t
*get_bridge(private_iface_t
*this)
182 * Implementation of iface_t.get_guest
184 static guest_t
* get_guest(private_iface_t
*this)
190 * destroy the tap device
192 static bool destroy_tap(private_iface_t
*this)
197 if (!iface_control(this->hostif
, FALSE
))
199 DBG1("bringing iface down failed: %m");
201 memset(&ifr
, 0, sizeof(ifr
));
202 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
203 strncpy(ifr
.ifr_name
, this->hostif
, sizeof(ifr
.ifr_name
) - 1);
205 tap
= open(TAP_DEVICE
, O_RDWR
);
208 DBG1("unable to open tap device %s: %m", TAP_DEVICE
);
211 if (ioctl(tap
, TUNSETIFF
, &ifr
) < 0 ||
212 ioctl(tap
, TUNSETPERSIST
, 0) < 0)
214 DBG1("removing %s failed: %m", this->hostif
);
223 * create the tap device
225 static char* create_tap(private_iface_t
*this)
230 memset(&ifr
, 0, sizeof(ifr
));
231 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
232 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s-%s",
233 this->guest
->get_name(this->guest
), this->guestif
);
235 tap
= open(TAP_DEVICE
, O_RDWR
);
238 DBG1("unable to open tap device %s: %m", TAP_DEVICE
);
241 if (ioctl(tap
, TUNSETIFF
, &ifr
) < 0 ||
242 ioctl(tap
, TUNSETPERSIST
, 1) < 0 ||
243 ioctl(tap
, TUNSETOWNER
, 0))
245 DBG1("creating new tap device failed: %m");
250 return strdup(ifr
.ifr_name
);
254 * Implementation of iface_t.destroy.
256 static void destroy(private_iface_t
*this)
260 this->bridge
->disconnect_iface(this->bridge
, &this->public);
262 /* TODO: iface mgmt is not blocking yet, so wait some ticks */
264 this->mconsole
->del_iface(this->mconsole
, this->guestif
);
272 * create the iface instance
274 iface_t
*iface_create(char *name
, guest_t
*guest
, mconsole_t
*mconsole
)
276 private_iface_t
*this = malloc_thing(private_iface_t
);
278 this->public.get_hostif
= (char*(*)(iface_t
*))get_hostif
;
279 this->public.get_guestif
= (char*(*)(iface_t
*))get_guestif
;
280 this->public.add_address
= (bool(*)(iface_t
*, host_t
*addr
))add_address
;
281 this->public.create_address_enumerator
= (enumerator_t
*(*)(iface_t
*))create_address_enumerator
;
282 this->public.delete_address
= (bool(*)(iface_t
*, host_t
*addr
))delete_address
;
283 this->public.set_bridge
= (void(*)(iface_t
*, bridge_t
*))set_bridge
;
284 this->public.get_bridge
= (bridge_t
*(*)(iface_t
*))get_bridge
;
285 this->public.get_guest
= (guest_t
*(*)(iface_t
*))get_guest
;
286 this->public.destroy
= (void*)destroy
;
288 this->mconsole
= mconsole
;
289 this->guestif
= strdup(name
);
291 this->hostif
= create_tap(this);
293 if (this->hostif
== NULL
)
300 if (!this->mconsole
->add_iface(this->mconsole
, this->guestif
, this->hostif
))
302 DBG1("creating interface '%s' in guest failed", this->guestif
);
309 if (!iface_control(this->hostif
, TRUE
))
311 DBG1("bringing iface '%s' up failed: %m", this->hostif
);
313 return &this->public;