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)
86 METHOD(iface_t
, get_guestif
, char*,
87 private_iface_t
*this)
92 METHOD(iface_t
, get_hostif
, char*,
93 private_iface_t
*this)
98 METHOD(iface_t
, add_address
, bool,
99 private_iface_t
*this, host_t
*addr
, int bits
)
101 return (this->guest
->exec(this->guest
, NULL
, NULL
,
102 "exec ip addr add %H/%d dev %s", addr
, bits
, this->guestif
) == 0);
106 * compile a list of the addresses of an interface
108 static void compile_address_list(linked_list_t
*list
, char *address
)
110 host_t
*host
= host_create_from_string(address
, 0);
113 list
->insert_last(list
, host
);
118 * delete the list of addresses
120 static void destroy_address_list(linked_list_t
*list
)
122 list
->destroy_offset(list
, offsetof(host_t
, destroy
));
125 METHOD(iface_t
, create_address_enumerator
, enumerator_t
*,
126 private_iface_t
*this)
128 linked_list_t
*addresses
= linked_list_create();
129 this->guest
->exec_str(this->guest
, (void(*)(void*,char*))compile_address_list
,
131 "exec ip addr list dev %s scope global | "
132 "grep '^ \\+\\(inet6\\? \\)' | "
133 "awk -F '( +|/)' '{ print $3 }'", this->guestif
);
134 return enumerator_create_cleaner(addresses
->create_enumerator(addresses
),
135 (void(*)(void*))destroy_address_list
, addresses
);
138 METHOD(iface_t
, delete_address
, bool,
139 private_iface_t
*this, host_t
*addr
, int bits
)
141 return (this->guest
->exec(this->guest
, NULL
, NULL
,
142 "exec ip addr del %H/%d dev %s", addr
, bits
, this->guestif
) == 0);
145 METHOD(iface_t
, set_bridge
, void,
146 private_iface_t
*this, bridge_t
*bridge
)
148 if (this->bridge
== NULL
&& bridge
)
150 this->guest
->exec(this->guest
, NULL
, NULL
,
151 "exec ip link set %s up", this->guestif
);
153 else if (this->bridge
&& bridge
== NULL
)
155 this->guest
->exec(this->guest
, NULL
, NULL
,
156 "exec ip link set %s down", this->guestif
);
158 this->bridge
= bridge
;
161 METHOD(iface_t
, get_bridge
, bridge_t
*,
162 private_iface_t
*this)
167 METHOD(iface_t
, get_guest
, guest_t
*,
168 private_iface_t
*this)
174 * destroy the tap device
176 static bool destroy_tap(private_iface_t
*this)
181 if (!iface_control(this->hostif
, FALSE
))
183 DBG1(DBG_LIB
, "bringing iface down failed: %m");
185 memset(&ifr
, 0, sizeof(ifr
));
186 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
187 strncpy(ifr
.ifr_name
, this->hostif
, sizeof(ifr
.ifr_name
) - 1);
189 tap
= open(TAP_DEVICE
, O_RDWR
);
192 DBG1(DBG_LIB
, "unable to open tap device %s: %m", TAP_DEVICE
);
195 if (ioctl(tap
, TUNSETIFF
, &ifr
) < 0 ||
196 ioctl(tap
, TUNSETPERSIST
, 0) < 0)
198 DBG1(DBG_LIB
, "removing %s failed: %m", this->hostif
);
207 * create the tap device
209 static char* create_tap(private_iface_t
*this)
214 memset(&ifr
, 0, sizeof(ifr
));
215 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
216 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s-%s",
217 this->guest
->get_name(this->guest
), this->guestif
);
219 tap
= open(TAP_DEVICE
, O_RDWR
);
222 DBG1(DBG_LIB
, "unable to open tap device %s: %m", TAP_DEVICE
);
225 if (ioctl(tap
, TUNSETIFF
, &ifr
) < 0 ||
226 ioctl(tap
, TUNSETPERSIST
, 1) < 0 ||
227 ioctl(tap
, TUNSETOWNER
, 0))
229 DBG1(DBG_LIB
, "creating new tap device failed: %m");
234 return strdup(ifr
.ifr_name
);
237 METHOD(iface_t
, destroy
, void,
238 private_iface_t
*this)
242 this->bridge
->disconnect_iface(this->bridge
, &this->public);
244 /* TODO: iface mgmt is not blocking yet, so wait some ticks */
246 this->mconsole
->del_iface(this->mconsole
, this->guestif
);
254 * create the iface instance
256 iface_t
*iface_create(char *name
, guest_t
*guest
, mconsole_t
*mconsole
)
258 private_iface_t
*this;
262 .get_hostif
= _get_hostif
,
263 .get_guestif
= _get_guestif
,
264 .add_address
= _add_address
,
265 .create_address_enumerator
= _create_address_enumerator
,
266 .delete_address
= _delete_address
,
267 .set_bridge
= _set_bridge
,
268 .get_bridge
= _get_bridge
,
269 .get_guest
= _get_guest
,
272 .mconsole
= mconsole
,
273 .guestif
= strdup(name
),
276 this->hostif
= create_tap(this);
277 if (this->hostif
== NULL
)
284 if (!this->mconsole
->add_iface(this->mconsole
, this->guestif
, this->hostif
))
286 DBG1(DBG_LIB
, "creating interface '%s' in guest failed", this->guestif
);
293 if (!iface_control(this->hostif
, TRUE
))
295 DBG1(DBG_LIB
, "bringing iface '%s' up failed: %m", this->hostif
);
297 return &this->public;