From 63f35c96f2a20c3bd9ec1e2128c11f94842ff2fc Mon Sep 17 00:00:00 2001 From: Pawel Wieczorkiewicz Date: Tue, 11 Mar 2014 17:17:21 +0100 Subject: [PATCH] tap: initial support, no ifcfg yet Merge with existing TUN and change to TUN/TAP (tuntap) when possible to avoid code duplications. --- etc/org.opensuse.Network.conf | 4 + include/Makefile.am | 2 +- include/wicked/netinfo.h | 6 +- include/wicked/objectmodel.h | 1 + include/wicked/system.h | 10 +- include/wicked/{tun.h => tuntap.h} | 19 +- include/wicked/types.h | 2 +- samples/wicked/tap0.xml | 8 + samples/wicked/tun0.xml | 2 - schema/Makefile.am | 2 +- schema/openvpn.xml | 26 +- schema/tun.xml | 51 ---- schema/tuntap.xml | 94 ++++++++ schema/wicked.xml | 2 +- src/Makefile.am | 4 +- src/dbus-objects/interface.c | 4 +- src/dbus-objects/model.h | 4 +- src/dbus-objects/openvpn.c | 19 +- src/dbus-objects/tuntap.c | 370 +++++++++++++++++++++++++++++ src/ifconfig.c | 57 ++--- src/iflist.c | 29 ++- src/kernel.c | 93 +++----- src/kernel.h | 3 +- src/names.c | 4 +- src/netdev.c | 23 +- src/{tun.c => tuntap.c} | 71 +++--- 26 files changed, 649 insertions(+), 261 deletions(-) rename include/wicked/{tun.h => tuntap.h} (73%) create mode 100644 samples/wicked/tap0.xml delete mode 100644 schema/tun.xml create mode 100644 schema/tuntap.xml create mode 100644 src/dbus-objects/tuntap.c rename src/{tun.c => tuntap.c} (59%) diff --git a/etc/org.opensuse.Network.conf b/etc/org.opensuse.Network.conf index cd2e4d86c..5e8288c33 100644 --- a/etc/org.opensuse.Network.conf +++ b/etc/org.opensuse.Network.conf @@ -54,6 +54,10 @@ send_interface="org.opensuse.Network.TUN"/> + + -struct ni_tun { +struct ni_tuntap { ni_bool_t persistent; /* Always TRUE */ uid_t owner; gid_t group; }; -extern ni_tun_t * ni_tun_new(void); -extern void ni_tun_free(ni_tun_t *); -extern const char * ni_tun_validate(const ni_tun_t *); +extern ni_tuntap_t * ni_tuntap_new(void); +extern void ni_tuntap_free(ni_tuntap_t *); +extern const char * ni_tuntap_validate(const ni_tuntap_t *); -extern int ni_tun_parse_sysfs_attrs(const char *, ni_tun_t *); -#endif /* __WICKED_MACVLAN_H__ */ +extern int ni_tuntap_parse_sysfs_attrs(const char *, ni_tuntap_t *); + +#endif /* __WICKED_TUNTAP_H__ */ diff --git a/include/wicked/types.h b/include/wicked/types.h index 5c3673dae..dc5c88bfa 100644 --- a/include/wicked/types.h +++ b/include/wicked/types.h @@ -33,7 +33,7 @@ typedef struct ni_wireless_scan ni_wireless_scan_t; typedef struct ni_ethernet ni_ethernet_t; typedef struct ni_infiniband ni_infiniband_t; typedef struct ni_openvpn ni_openvpn_t; -typedef struct ni_tun ni_tun_t; +typedef struct ni_tuntap ni_tuntap_t; typedef struct ni_ppp ni_ppp_t; typedef struct ni_dcb ni_dcb_t; typedef struct ni_lldp ni_lldp_t; diff --git a/samples/wicked/tap0.xml b/samples/wicked/tap0.xml new file mode 100644 index 000000000..9b4573472 --- /dev/null +++ b/samples/wicked/tap0.xml @@ -0,0 +1,8 @@ + + tap0 + +
42:42:42:42:42
+ 0 + 0 +
+
diff --git a/samples/wicked/tun0.xml b/samples/wicked/tun0.xml index cb33dd422..ad57af10e 100644 --- a/samples/wicked/tun0.xml +++ b/samples/wicked/tun0.xml @@ -1,8 +1,6 @@ tun0 - - true 0 0 diff --git a/schema/Makefile.am b/schema/Makefile.am index 49697c5e6..4af0199f2 100644 --- a/schema/Makefile.am +++ b/schema/Makefile.am @@ -20,7 +20,7 @@ wicked_schema_files = \ ppp.xml \ protocol.xml \ types.xml \ - tun.xml \ + tuntap.xml \ vlan.xml \ wicked.xml \ wireless.xml diff --git a/schema/openvpn.xml b/schema/openvpn.xml index 3aa2fc464..bba0c923c 100644 --- a/schema/openvpn.xml +++ b/schema/openvpn.xml @@ -1,10 +1,12 @@ - + @@ -99,12 +101,6 @@ - - - - - - - - - - - - - - - - - - diff --git a/schema/tun.xml b/schema/tun.xml deleted file mode 100644 index 0dbd12c04..000000000 --- a/schema/tun.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - This link-layer service is provided by all TUN devices. Since there isn't a lot - to tune about a TUN once it has been created, this DBus interface doesn't offer - an own changeDevice() method (yet). - - TUN devices can be created through the org.opensuse.Network.TUN.Factory - factory interface. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/schema/tuntap.xml b/schema/tuntap.xml new file mode 100644 index 000000000..9819fbb75 --- /dev/null +++ b/schema/tuntap.xml @@ -0,0 +1,94 @@ + + + + This link-layer service is provided by all TUN devices. + + TUN devices can be created through the org.opensuse.Network.TUN.Factory + factory interface. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This link-layer service is provided by all TAP devices. + + TAP devices can be created through the org.opensuse.Network.TAP.Factory + factory interface. + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/wicked.xml b/schema/wicked.xml index 64ad0e7cb..45b2f0642 100644 --- a/schema/wicked.xml +++ b/schema/wicked.xml @@ -16,7 +16,7 @@ - + diff --git a/src/Makefile.am b/src/Makefile.am index 3a5116541..6101880e0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -93,7 +93,7 @@ libwicked_la_SOURCES = \ sysconfig.c \ sysfs.c \ timer.c \ - tun.c \ + tuntap.c \ update.c \ util.c \ vlan.c \ @@ -126,7 +126,7 @@ libwicked_dbus_objects_la_SOURCES = \ dbus-objects/openvpn.c \ dbus-objects/ppp.c \ dbus-objects/state.c \ - dbus-objects/tun.c \ + dbus-objects/tuntap.c \ dbus-objects/vlan.c \ dbus-objects/wireless.c diff --git a/src/dbus-objects/interface.c b/src/dbus-objects/interface.c index 4c17c25cd..689abd1aa 100644 --- a/src/dbus-objects/interface.c +++ b/src/dbus-objects/interface.c @@ -109,7 +109,7 @@ ni_objectmodel_register_netif_services(void) ni_objectmodel_register_netif_service(NI_IFTYPE_BRIDGE, &ni_objectmodel_bridge_service); ni_objectmodel_register_netif_service(NI_IFTYPE_WIRELESS, &ni_objectmodel_wireless_service); ni_objectmodel_register_netif_service(NI_IFTYPE_TUN, &ni_objectmodel_tun_service); - ni_objectmodel_register_netif_service(NI_IFTYPE_TUN, &ni_objectmodel_openvpn_service); + ni_objectmodel_register_netif_service(NI_IFTYPE_TAP, &ni_objectmodel_tap_service); ni_objectmodel_register_netif_service(NI_IFTYPE_INFINIBAND, &ni_objectmodel_ibparent_service); ni_objectmodel_register_netif_service(NI_IFTYPE_INFINIBAND_CHILD, &ni_objectmodel_ibchild_service); @@ -119,7 +119,7 @@ ni_objectmodel_register_netif_services(void) ni_objectmodel_register_netif_factory_service(&ni_objectmodel_macvlan_factory_service); ni_objectmodel_register_netif_factory_service(&ni_objectmodel_dummy_factory_service); ni_objectmodel_register_netif_factory_service(&ni_objectmodel_tun_factory_service); - ni_objectmodel_register_netif_factory_service(&ni_objectmodel_openvpn_factory_service); + ni_objectmodel_register_netif_factory_service(&ni_objectmodel_tap_factory_service); ni_objectmodel_register_netif_factory_service(&ni_objectmodel_ibchild_factory_service); /* Register all builtin naming services */ diff --git a/src/dbus-objects/model.h b/src/dbus-objects/model.h index b59f34f9b..4a9c664dc 100644 --- a/src/dbus-objects/model.h +++ b/src/dbus-objects/model.h @@ -97,12 +97,12 @@ extern ni_dbus_service_t ni_objectmodel_dummy_service; extern ni_dbus_service_t ni_objectmodel_dummy_factory_service; extern ni_dbus_service_t ni_objectmodel_tun_service; extern ni_dbus_service_t ni_objectmodel_tun_factory_service; +extern ni_dbus_service_t ni_objectmodel_tap_service; +extern ni_dbus_service_t ni_objectmodel_tap_factory_service; extern ni_dbus_service_t ni_objectmodel_ppp_base_service; extern ni_dbus_service_t ni_objectmodel_ppp_service; extern ni_dbus_service_t ni_objectmodel_ppp_factory_service; extern ni_dbus_service_t ni_objectmodel_pppoe_factory_service; -extern ni_dbus_service_t ni_objectmodel_openvpn_service; -extern ni_dbus_service_t ni_objectmodel_openvpn_factory_service; extern ni_dbus_service_t ni_objectmodel_ibparent_service; extern ni_dbus_service_t ni_objectmodel_ibchild_service; extern ni_dbus_service_t ni_objectmodel_ibchild_factory_service; diff --git a/src/dbus-objects/openvpn.c b/src/dbus-objects/openvpn.c index c164e31b7..14783f1c8 100644 --- a/src/dbus-objects/openvpn.c +++ b/src/dbus-objects/openvpn.c @@ -3,6 +3,7 @@ * * Copyright (C) 2012 Olaf Kirch */ +#if 0 #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -11,12 +12,13 @@ #include #include #include -#include +#include #include #include #include "model.h" #include "debug.h" +#if 0 extern ni_dbus_service_t ni_objectmodel_openvpn_service; static ni_netdev_t * __ni_objectmodel_openvpn_newlink(ni_netdev_t *, const char *, DBusError *); @@ -31,6 +33,7 @@ __ni_objectmodel_openvpn_device_arg(const ni_dbus_variant_t *dict) return ni_objectmodel_get_netif_argument(dict, NI_IFTYPE_TUN, &ni_objectmodel_openvpn_service); } +#endif /* * Create a new TUN interface @@ -70,7 +73,7 @@ __ni_objectmodel_openvpn_newlink(ni_netdev_t *cfg_ifp, const char *ifname, DBusE { ni_netconfig_t *nc = ni_global_state_handle(0); ni_netdev_t *new_dev = NULL; - const ni_tun_t *tun; + const ni_tuntap_t *cfg; const char *err; int rv; @@ -79,17 +82,18 @@ __ni_objectmodel_openvpn_newlink(ni_netdev_t *cfg_ifp, const char *ifname, DBusE ni_debug_dbus("OpenVPN.newDevice(name=%s)", ifname); if (ifname == NULL && !(ifname = ni_netdev_make_name(nc, "tun", 0))) { - dbus_set_error(error, DBUS_ERROR_FAILED, "Unable to create tun - too many interfaces"); + dbus_set_error(error, DBUS_ERROR_FAILED, + "Unable to create tun - too many interfaces"); goto out; } - tun = ni_netdev_get_tun(cfg_ifp); - if ((err = ni_tun_validate(tun))) { + cfg = ni_netdev_get_tuntap(cfg_ifp); + if ((err = ni_tuntap_validate(cfg))) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err); goto out; } - if ((rv = ni_system_tun_create(nc, ifname, tun, &new_dev)) < 0) { + if ((rv = ni_system_tuntap_create(nc, ifname, NI_IFTYPE_TUN, cfg, &new_dev)) < 0) { if (rv != -NI_ERROR_DEVICE_EXISTS || new_dev == NULL || (ifname && new_dev && !ni_string_eq(new_dev->name, ifname))) { ni_dbus_set_error_from_code(error, rv, @@ -141,7 +145,7 @@ ni_objectmodel_openvpn_delete(ni_dbus_object_t *object, const ni_dbus_method_t * * the configuration files, keys etc. */ ni_netdev_set_openvpn(dev, NULL); - if ((rv = ni_system_tun_delete(dev)) < 0) { + if ((rv = ni_system_tuntap_delete(dev)) < 0) { ni_dbus_set_error_from_code(error, rv, "Cannot delete OpenVPN interface %s", dev->name); return FALSE; } @@ -203,4 +207,5 @@ ni_dbus_service_t ni_objectmodel_openvpn_service = { .properties = ni_objectmodel_openvpn_property_table, }; +#endif diff --git a/src/dbus-objects/tuntap.c b/src/dbus-objects/tuntap.c new file mode 100644 index 000000000..27d559cd6 --- /dev/null +++ b/src/dbus-objects/tuntap.c @@ -0,0 +1,370 @@ +/* + * DBus encapsulation for tun/tap interfaces + * + * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, see or write + * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Authors: + * Olaf Kirch + * Marius Tomaschewski + * Pawel Wieczorkiewicz + * + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include "model.h" +#include "debug.h" + +/* + * Create a new TUN/TAP interface + */ +static ni_netdev_t * +__ni_objectmodel_tuntap_create(ni_netdev_t *cfg, DBusError *error) +{ + ni_netconfig_t *nc = ni_global_state_handle(0); + ni_netdev_t *dev = NULL; + const char *iftype; + const ni_tuntap_t *tuntap; + const char *err; + int rv; + + iftype = ni_linktype_type_to_name(cfg->link.type); + if (cfg->link.type != NI_IFTYPE_TUN && cfg->link.type != NI_IFTYPE_TAP) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "BUG: Cannot handle %s type in tun/tap factory", iftype); + return NULL; + } + + ni_debug_dbus("%s.newDevice(name=%s)", iftype, cfg->name); + tuntap = ni_netdev_get_tuntap(cfg); + if ((err = ni_tuntap_validate(tuntap))) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err); + return NULL; + } + + if (ni_string_empty(cfg->name)) { + if (ni_string_empty(cfg->name) && + (cfg->name = (char *) ni_netdev_make_name(nc, iftype, 0))) { + ni_string_dup(&cfg->name, cfg->name); + } else { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Unable to create %s interface: " + "name argument missed", iftype); + return NULL; + } + cfg->name = NULL; + } else if(!ni_string_eq(cfg->name, cfg->name)) { + ni_string_dup(&cfg->name, cfg->name); + } + + if (cfg->link.type == NI_IFTYPE_TAP && cfg->link.hwaddr.len) { + if (cfg->link.hwaddr.type == ARPHRD_VOID) + cfg->link.hwaddr.type = ARPHRD_ETHER; + + if (cfg->link.hwaddr.type != ARPHRD_ETHER + || cfg->link.hwaddr.len != ni_link_address_length(ARPHRD_ETHER)) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, + "Cannot create %s interface: " + "invalid ethernet address '%s'", iftype, + ni_link_address_print(&cfg->link.hwaddr)); + return NULL; + } + } + + if ((rv = ni_system_tuntap_create(nc, cfg, &dev)) < 0) { + if (rv != -NI_ERROR_DEVICE_EXISTS || dev == NULL + || (cfg->name && dev && !ni_string_eq(dev->name, cfg->name))) { + ni_dbus_set_error_from_code(error, rv, + "Unable to create %s interface %s", + iftype, cfg->name); + return NULL; + } + ni_debug_dbus("%s interface exists (and name matches)", iftype); + } + + if (dev->link.type != cfg->link.type) { + dbus_set_error(error, + DBUS_ERROR_FAILED, + "Unable to create %s: existing interface %s is of type %s", + iftype, dev->name, ni_linktype_type_to_name(dev->link.type)); + return NULL; + } + + return dev; +} + +static inline ni_netdev_t * +__ni_objectmodel_tuntap_device_arg(const ni_dbus_variant_t *dict, + const ni_iftype_t iftype) +{ + switch (iftype) { + case NI_IFTYPE_TUN: + return ni_objectmodel_get_netif_argument(dict, iftype, + &ni_objectmodel_tun_service); + case NI_IFTYPE_TAP: + return ni_objectmodel_get_netif_argument(dict, iftype, + &ni_objectmodel_tap_service); + default: + return NULL; + } +} + +static dbus_bool_t +__ni_objectmodel_tuntap_newlink(ni_iftype_t iftype, ni_dbus_object_t *factory_object, + const ni_dbus_method_t *method, + unsigned int argc, const ni_dbus_variant_t *argv, + ni_dbus_message_t *reply, DBusError *error) +{ + ni_dbus_server_t *server = ni_dbus_object_get_server(factory_object); + const char *ifname = NULL; + ni_netdev_t *dev; + ni_netdev_t *cfg; + + NI_TRACE_ENTER(); + ni_assert(argc == 2); + + if (!ni_dbus_variant_get_string(&argv[0], &ifname) || + !(cfg = __ni_objectmodel_tuntap_device_arg(&argv[1], iftype))) { + return ni_dbus_error_invalid_args(error, + factory_object->path, + method->name); + } + + ni_string_dup(&cfg->name, ifname); + dev = __ni_objectmodel_tuntap_create(cfg, error); + + ni_netdev_put(cfg); + if (!dev) + return FALSE; + return ni_objectmodel_netif_factory_result(server, reply, dev, NULL, error); +} + +static dbus_bool_t +ni_objectmodel_tun_newlink(ni_dbus_object_t *factory_object, + const ni_dbus_method_t *method, + unsigned int argc, const ni_dbus_variant_t *argv, + ni_dbus_message_t *reply, DBusError *error) +{ + return __ni_objectmodel_tuntap_newlink(NI_IFTYPE_TUN, factory_object, + method, argc, argv, reply, error); +} + +static dbus_bool_t +ni_objectmodel_tap_newlink(ni_dbus_object_t *factory_object, + const ni_dbus_method_t *method, + unsigned int argc, const ni_dbus_variant_t *argv, + ni_dbus_message_t *reply, DBusError *error) +{ + return __ni_objectmodel_tuntap_newlink(NI_IFTYPE_TAP, factory_object, + method, argc, argv, reply, error); +} + +static dbus_bool_t +ni_objectmodel_tuntap_change(ni_dbus_object_t *object, const ni_dbus_method_t *method, + unsigned int argc, const ni_dbus_variant_t *argv, + ni_dbus_message_t *reply, DBusError *error) +{ + ni_netconfig_t *nc = ni_global_state_handle(0); + ni_netdev_t *dev, *cfg; + ni_tuntap_t *tuntap; + const char *err; + const char *iftype_name; + + /* we've already checked that argv matches our signature */ + ni_assert(argc == 1); + + if (!(dev = ni_objectmodel_unwrap_netif(object, error)) || + !(cfg = __ni_objectmodel_tuntap_device_arg(&argv[0], dev->link.type)) || + !(ni_netdev_get_tuntap(dev))) { + ni_dbus_error_invalid_args(error, object->path, method->name); + return FALSE; + } + + /* changeDevice method is only needed in case of TAP devices */ + if (dev->link.type != NI_IFTYPE_TAP) + return TRUE; + + iftype_name = ni_linktype_type_to_name(dev->link.type); + + tuntap = ni_netdev_get_tuntap(cfg); + if ((err = ni_tuntap_validate(tuntap))) { + dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err); + return FALSE; + } + + cfg->link.ifindex = dev->link.ifindex; + if (ni_string_empty(cfg->name)) + ni_string_dup(&cfg->name, dev->name); + + if (ni_netdev_device_is_up(dev)) { + ni_debug_objectmodel("Skipping %s changeDevice call on %s: " + "device is up", iftype_name, dev->name); + return TRUE; + } + + if (ni_system_tap_change(nc, dev, cfg) < 0) { + dbus_set_error(error, + DBUS_ERROR_FAILED, + "Unable to change %s properties on interface %s", + iftype_name, dev->name); + return FALSE; + } + + if (cfg->link.hwaddr.type == ARPHRD_VOID) + cfg->link.hwaddr.type = ARPHRD_ETHER; + if (ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) { + ni_error("Unable to change hwaddr on %s interface %s", + iftype_name, dev->name); + /* fail? */ + } + + return TRUE; +} + + +/* + * Delete a TUN/TAP interface + */ +dbus_bool_t +ni_objectmodel_tuntap_delete(ni_dbus_object_t *object, const ni_dbus_method_t *method, + unsigned int argc, const ni_dbus_variant_t *argv, + ni_dbus_message_t *reply, DBusError *error) +{ + ni_netdev_t *dev; + int rv; + + if (!(dev = ni_objectmodel_unwrap_netif(object, error))) + return FALSE; + + NI_TRACE_ENTER_ARGS("dev=%s", dev->name); + if ((rv = ni_system_tuntap_delete(dev) < 0)) { + dbus_set_error(error, DBUS_ERROR_FAILED, + "Error deleting TUN/TAP interface %s: %s", + dev->name, ni_strerror(rv)); + return FALSE; + } + + ni_client_state_drop(dev->link.ifindex); + ni_dbus_object_free(object); + return TRUE; +} + +/* + * Helper function to obtain TUN/TAP config from dbus object + */ +static void * +ni_objectmodel_get_tuntap(const ni_dbus_object_t *object, + ni_bool_t write_access, DBusError *error) +{ + ni_netdev_t *dev; + + if (!(dev = ni_objectmodel_unwrap_netif(object, error))) + return NULL; + + if (!write_access) + return dev->tuntap; + + return ni_netdev_get_tuntap(dev); +} + +static dbus_bool_t +__ni_objectmodel_tap_get_address(const ni_dbus_object_t *object, + const ni_dbus_property_t *property, + ni_dbus_variant_t *result, + DBusError *error) +{ + ni_netdev_t *dev; + + if (!(dev = ni_objectmodel_unwrap_netif(object, error))) + return FALSE; + return __ni_objectmodel_get_hwaddr(result, &dev->link.hwaddr); +} + +static dbus_bool_t +__ni_objectmodel_tap_set_address(ni_dbus_object_t *object, + const ni_dbus_property_t *property, + const ni_dbus_variant_t *argument, + DBusError *error) +{ + ni_netdev_t *dev; + + if (!(dev = ni_objectmodel_unwrap_netif(object, error))) + return FALSE; + return __ni_objectmodel_set_hwaddr(argument, &dev->link.hwaddr); +} + +const ni_dbus_property_t ni_objectmodel_tun_property_table[] = { + NI_DBUS_GENERIC_UINT32_PROPERTY(tuntap, owner, owner, RO), + NI_DBUS_GENERIC_UINT32_PROPERTY(tuntap, group, group, RO), + { NULL } +}; + +const ni_dbus_property_t ni_objectmodel_tap_property_table[] = { + __NI_DBUS_PROPERTY(DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_BYTE_AS_STRING, + address, __ni_objectmodel_tap, RO), + NI_DBUS_GENERIC_UINT32_PROPERTY(tuntap, owner, owner, RO), + NI_DBUS_GENERIC_UINT32_PROPERTY(tuntap, group, group, RO), + { NULL } +}; + +static ni_dbus_method_t ni_objectmodel_tuntap_methods[] = { + { "changeDevice", "a{sv}", ni_objectmodel_tuntap_change }, + { "deleteDevice", "", ni_objectmodel_tuntap_delete }, + { NULL } +}; + +static ni_dbus_method_t ni_objectmodel_tun_factory_methods[] = { + { "newDevice", "sa{sv}", ni_objectmodel_tun_newlink }, + { NULL } +}; + +static ni_dbus_method_t ni_objectmodel_tap_factory_methods[] = { + { "newDevice", "sa{sv}", ni_objectmodel_tap_newlink }, + { NULL } +}; + +ni_dbus_service_t ni_objectmodel_tun_factory_service = { + .name = NI_OBJECTMODEL_TUN_INTERFACE ".Factory", + .methods = ni_objectmodel_tun_factory_methods, +}; + +ni_dbus_service_t ni_objectmodel_tap_factory_service = { + .name = NI_OBJECTMODEL_TAP_INTERFACE ".Factory", + .methods = ni_objectmodel_tap_factory_methods, +}; + +ni_dbus_service_t ni_objectmodel_tun_service = { + .name = NI_OBJECTMODEL_TUN_INTERFACE, + .methods = ni_objectmodel_tuntap_methods, + .properties = ni_objectmodel_tun_property_table, +}; + +ni_dbus_service_t ni_objectmodel_tap_service = { + .name = NI_OBJECTMODEL_TAP_INTERFACE, + .methods = ni_objectmodel_tuntap_methods, + .properties = ni_objectmodel_tap_property_table, +}; diff --git a/src/ifconfig.c b/src/ifconfig.c index 5c376166e..8005c2f53 100644 --- a/src/ifconfig.c +++ b/src/ifconfig.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include @@ -273,15 +273,9 @@ ni_system_interface_delete(ni_netconfig_t *nc, const char *ifname) case NI_IFTYPE_DUMMY: case NI_IFTYPE_VLAN: case NI_IFTYPE_MACVLAN: - if (__ni_rtnl_link_down(dev, RTM_DELLINK)) { - ni_error("could not destroy %s interface %s", - ni_linktype_type_to_name(dev->link.type), dev->name); - return -1; - } - break; - case NI_IFTYPE_TUN: - if (__ni_tuntap_delete(dev->name) < 0) { + case NI_IFTYPE_TAP: + if (__ni_rtnl_link_down(dev, RTM_DELLINK)) { ni_error("could not destroy %s interface %s", ni_linktype_type_to_name(dev->link.type), dev->name); return -1; @@ -1171,23 +1165,31 @@ ni_system_bond_remove_slave(ni_netconfig_t *nc, ni_netdev_t *dev, unsigned int s return 0; } +int +ni_system_tap_change(ni_netconfig_t *nc, ni_netdev_t *dev, const ni_netdev_t *cfg) +{ + return __ni_rtnl_link_change(dev, cfg); +} + /* - * Create a tun interface + * Create a tun/tap interface */ int -ni_system_tun_create(ni_netconfig_t *nc, const char *ifname, - const ni_tun_t *cfg, ni_netdev_t **dev_ret) +ni_system_tuntap_create(ni_netconfig_t *nc, const ni_netdev_t *cfg, ni_netdev_t **dev_ret) { + const char *iftype_name; ni_netdev_t *dev; - char *newname; + ni_assert(cfg && dev_ret); *dev_ret = NULL; + iftype_name = ni_linktype_type_to_name(cfg->link.type); - dev = ni_netdev_by_name(nc, ifname); + dev = ni_netdev_by_name(nc, cfg->name); if (dev != NULL) { /* This is not necessarily an error */ - if (dev->link.type == NI_IFTYPE_TUN) { - ni_debug_ifconfig("A tun interface %s already exists", dev->name); + if (dev->link.type == cfg->link.type) { + ni_debug_ifconfig("A %s interface %s already exists", iftype_name, + dev->name); *dev_ret = dev; } else { ni_error("A %s interface with the name %s already exists", @@ -1196,26 +1198,27 @@ ni_system_tun_create(ni_netconfig_t *nc, const char *ifname, return -NI_ERROR_DEVICE_EXISTS; } - ni_debug_ifconfig("%s: creating tun interface", ifname); - if ((newname = __ni_tuntap_create(ifname, cfg)) == NULL) { - ni_error("__ni_tuntap_create(%s) failed", ifname); + ni_debug_ifconfig("%s: creating %s interface", iftype_name, cfg->name); + if (__ni_tuntap_create(cfg) < 0) { + ni_error("__ni_tuntap_create(%s) failed for %s interface ", cfg->name, + iftype_name); return -1; } /* Refresh interface status */ __ni_system_refresh_interfaces(nc); - dev = ni_netdev_by_name(nc, newname); - free(newname); + dev = ni_netdev_by_name(nc, cfg->name); if (dev == NULL) { - ni_error("tried to create tun interface %s; still not found", ifname); + ni_error("tried to create %s interface %s; still not found", + iftype_name, cfg->name); return -1; } - if (!ni_netdev_get_tun(dev)) { + if (!ni_netdev_get_tuntap(dev)) { ni_error("found new interface name %s but with type %s", - ifname, ni_linktype_type_to_name(dev->link.type)); + cfg->name, ni_linktype_type_to_name(dev->link.type)); return -1; } @@ -1224,14 +1227,14 @@ ni_system_tun_create(ni_netconfig_t *nc, const char *ifname, } /* - * Delete a tun interface + * Delete a tun/tap interface */ int -ni_system_tun_delete(ni_netdev_t *dev) +ni_system_tuntap_delete(ni_netdev_t *dev) { int rv; - if ((rv = __ni_tuntap_delete(dev->name)) < 0) { + if (__ni_rtnl_link_down(dev, RTM_DELLINK)) { ni_error("could not destroy tun/tap interface %s", dev->name); return rv; } diff --git a/src/iflist.c b/src/iflist.c index e5e328dbf..103f26042 100644 --- a/src/iflist.c +++ b/src/iflist.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #if defined(HAVE_RTA_MARK) @@ -64,7 +64,7 @@ static int __ni_discover_addrconf(ni_netdev_t *); static int __ni_discover_infiniband(ni_netdev_t *, ni_netconfig_t *); static int __ni_discover_vlan(ni_netdev_t *, struct nlattr **, ni_netconfig_t *); static int __ni_discover_macvlan(ni_netdev_t *, struct nlattr **, ni_netconfig_t *); -static int __ni_discover_tun(ni_netdev_t *); +static int __ni_discover_tuntap(ni_netdev_t *); static ni_route_t * __ni_netdev_add_autoconf_prefix(ni_netdev_t *, const ni_sockaddr_t *, unsigned int, const struct prefix_cacheinfo *); static ni_addrconf_lease_t *__ni_netdev_get_autoconf_lease(ni_netdev_t *, unsigned int); @@ -1002,7 +1002,8 @@ __ni_netdev_process_newlink(ni_netdev_t *dev, struct nlmsghdr *h, break; case NI_IFTYPE_TUN: - __ni_discover_tun(dev); + case NI_IFTYPE_TAP: + __ni_discover_tuntap(dev); break; case NI_IFTYPE_WIRELESS: @@ -1101,20 +1102,26 @@ __ni_discover_macvlan(ni_netdev_t *dev, struct nlattr **tb, ni_netconfig_t *nc) } int -__ni_discover_tun(ni_netdev_t *dev) +__ni_discover_tuntap(ni_netdev_t *dev) { - ni_tun_t *tun; + ni_tuntap_t *cfg; int rv = -1; - if (!dev || dev->link.type != NI_IFTYPE_TUN) { - ni_error("%s: Unable to discover tun interface details", - dev ? dev->name : NULL); + if (!dev) { + ni_error("Unable to discover NULL interface details"); + return rv; + } + + if (dev->link.type != NI_IFTYPE_TUN && dev->link.type != NI_IFTYPE_TAP) { + ni_error("%s: Attempt to discover %s interface details for TUN/TAP", + ni_linktype_type_to_name(dev->link.type), dev->name); return rv; } - tun = ni_netdev_get_tun(dev); - if ((rv = ni_tun_parse_sysfs_attrs(dev->name, tun) < 0)) - ni_error("error retrieving tun attribute from sysfs"); + cfg = ni_netdev_get_tuntap(dev); + if ((rv = ni_tuntap_parse_sysfs_attrs(dev->name, cfg) < 0)) + ni_error("error retrieving %s attribute from sysfs", + ni_linktype_type_to_name(dev->link.type)); return rv; } diff --git a/src/kernel.c b/src/kernel.c index fbe682fad..559a7900d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -32,7 +32,7 @@ #include "sysfs.h" #include "kernel.h" #include -#include +#include /* FIXME: we should really make this configurable */ #ifndef CONFIG_TUNTAP_CHRDEV_PATH @@ -217,76 +217,55 @@ __ni_tuntap_open_dev(void) return devfd; } -char * -__ni_tuntap_create(const char *ifname, const ni_tun_t *cfg) +int +__ni_tuntap_create(const ni_netdev_t *cfg) { - unsigned int index = 0; struct ifreq ifr; int devfd; - char *retname = NULL; - - if ((devfd = __ni_tuntap_open_dev()) < 0) - return NULL; + uid_t owner; + gid_t group; + int rv = -1; - memset(&ifr, 0, sizeof(ifr)); - ifr.ifr_flags = IFF_TUN | IFF_TUN_EXCL; - - while (1) { - /* If the caller didn't specify an interface name, we try - * all tunX names in turn until we find a free one. - */ - if (ifname != NULL) - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - else - snprintf(ifr.ifr_name, IFNAMSIZ, "tun%u", index++); + if (!cfg || !cfg->tuntap || ni_string_empty(cfg->name)) + goto error; - if (ioctl(devfd, TUNSETIFF, &ifr) >= 0) { - retname = xstrdup(ifr.ifr_name); + if ((NI_IFTYPE_TUN != cfg->link.type && NI_IFTYPE_TAP != cfg->link.type) || + (devfd = __ni_tuntap_open_dev()) < 0) { + goto error; + } - if (ioctl(devfd, TUNSETPERSIST, cfg->persistent) == 0 && - ioctl(devfd, TUNSETOWNER, cfg->owner) == 0 && - ioctl(devfd, TUNSETGROUP, cfg->group) == 0) { - break; - } - } + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_NO_PI; + ifr.ifr_flags = (NI_IFTYPE_TUN == cfg->link.type ? IFF_TUN : IFF_TAP); + strncpy(ifr.ifr_name, cfg->name, sizeof(ifr.ifr_name) - 1); - if (errno != EBUSY || ifname) { - ni_error("failed to create tun device: %m"); - goto done; - } - } + if ((rv = ioctl(devfd, TUNSETIFF, (void *) &ifr)) < 0) + goto error; -done: - close(devfd); - return retname; -} + if ((rv = ioctl(devfd, TUNSETPERSIST, cfg->tuntap->persistent)) < 0) + goto error; -int -__ni_tuntap_delete(const char *ifname) -{ - struct ifreq ifr; - int devfd, rv = -1; + owner = cfg->tuntap->owner; + group = cfg->tuntap->group; - ni_debug_ifconfig("%s(%s)", __func__, ifname); - if ((devfd = __ni_tuntap_open_dev()) < 0) - return -1; + if (owner == -1U && group == -1U) + owner = geteuid(); - /* To destroy the interface, attach it to the chrdev, unset the - * PERSIST flag, and close the chrdev. */ - memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - ifr.ifr_flags = IFF_TUN; + if (owner != -1U) { + if ((rv = ioctl(devfd, TUNSETOWNER, owner)) < 0) + goto error; + } - if (ioctl(devfd, TUNSETIFF, &ifr) < 0) { - ni_error("%s: cannot attach tun device: %m", ifname); - } else - if (ioctl(devfd, TUNSETPERSIST, 0) < 0) { - ni_error("%s: unable to unset persist flag: %m", ifname); - } else { - rv = 0; + if (group != -1U) { + if ((rv = ioctl(devfd, TUNSETGROUP, group)) < 0) + goto error; } - close(devfd); + return 0; + +error: + ni_error("failed to create %s device: %m", + ni_linktype_type_to_name(cfg->link.type)); return rv; } diff --git a/src/kernel.h b/src/kernel.h index feddad627..24869b582 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -61,8 +61,7 @@ extern int __ni_brioctl_del_port(const char *, unsigned int); extern int __ni_wireless_get_name(const char *, char *, size_t); extern int __ni_wireless_get_essid(const char *, char *, size_t); -extern char * __ni_tuntap_create(const char *, const ni_tun_t *); -extern int __ni_tuntap_delete(const char *); +extern int __ni_tuntap_create(const ni_netdev_t *); extern char * __ni_ppp_create_device(ni_ppp_t *, const char *); diff --git a/src/names.c b/src/names.c index 7725c0ec5..09b7b1f3b 100644 --- a/src/names.c +++ b/src/names.c @@ -35,8 +35,8 @@ static const ni_intmap_t __linktype_names[] = { { "isdn", NI_IFTYPE_ISDN }, { "tunnel", NI_IFTYPE_TUNNEL }, { "tunnel6", NI_IFTYPE_TUNNEL6 }, - { "virtual-tunnel", NI_IFTYPE_TUN }, - { "virtual-tap", NI_IFTYPE_TAP }, + { "tun", NI_IFTYPE_TUN }, + { "tap", NI_IFTYPE_TAP }, { "dummy", NI_IFTYPE_DUMMY }, { "ctcm", NI_IFTYPE_CTCM }, { "iucv", NI_IFTYPE_IUCV }, diff --git a/src/netdev.c b/src/netdev.c index 6a5c24435..eb1b10767 100644 --- a/src/netdev.c +++ b/src/netdev.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -184,23 +184,23 @@ ni_netdev_set_vlan(ni_netdev_t *dev, ni_vlan_t *vlan) /* * Get the interface's TUN/TAP information */ -ni_tun_t * -ni_netdev_get_tun(ni_netdev_t *dev) +ni_tuntap_t * +ni_netdev_get_tuntap(ni_netdev_t *dev) { - if (dev->link.type != NI_IFTYPE_TUN) + if (dev->link.type != NI_IFTYPE_TUN && dev->link.type != NI_IFTYPE_TAP) return NULL; - if (!dev->tun) - dev->tun = ni_tun_new(); - return dev->tun; + if (!dev->tuntap) + dev->tuntap = ni_tuntap_new(); + return dev->tuntap; } void -ni_netdev_set_tun(ni_netdev_t *dev, ni_tun_t *tun) +ni_netdev_set_tuntap(ni_netdev_t *dev, ni_tuntap_t *cfg) { - if (dev->tun) - ni_tun_free(dev->tun); - dev->tun = tun; + if (dev->tuntap) + ni_tuntap_free(dev->tuntap); + dev->tuntap = cfg; } /* @@ -753,6 +753,7 @@ static ni_intmap_t __ifname_types[] = { { "ipip", NI_IFTYPE_TUNNEL }, { "sit", NI_IFTYPE_SIT }, { "tun", NI_IFTYPE_TUN }, + { "tap", NI_IFTYPE_TAP }, { NULL } }; diff --git a/src/tun.c b/src/tuntap.c similarity index 59% rename from src/tun.c rename to src/tuntap.c index 10a891257..7a49cb1d0 100644 --- a/src/tun.c +++ b/src/tuntap.c @@ -1,5 +1,5 @@ /* - * DBus encapsulation for tun/tap interfaces + * Routines for handling tun/tap device settings * * Copyright (C) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. * @@ -31,7 +31,7 @@ #include #include -#include +#include #include "netinfo_priv.h" #include "util_priv.h" @@ -43,97 +43,82 @@ * Initialize defaults */ static inline void -__ni_tun_init(ni_tun_t *tun) +__ni_tuntap_init(ni_tuntap_t *cfg) { - memset(tun, 0, sizeof(*tun)); - tun->persistent = TRUE; + memset(cfg, 0, sizeof(*cfg)); + cfg->persistent = TRUE; } /* - * Create a tun config + * Create a tun/tap config */ -ni_tun_t * -ni_tun_new(void) +ni_tuntap_t * +ni_tuntap_new(void) { - ni_tun_t *tun; + ni_tuntap_t *cfg; - tun = xcalloc(1, sizeof(ni_tun_t)); - __ni_tun_init(tun); + cfg = xcalloc(1, sizeof(ni_tuntap_t)); + __ni_tuntap_init(cfg); - return tun; + return cfg; } /* - * Free tun configuration + * Free tun/tap configuration */ void -ni_tun_free(ni_tun_t *tun) +ni_tuntap_free(ni_tuntap_t *cfg) { - free(tun); + free(cfg); } /* - * Check whether the given tun settings are valid + * Check whether the given tun/tap settings are valid */ const char * -ni_tun_validate(const ni_tun_t *tun) +ni_tuntap_validate(const ni_tuntap_t *cfg) { - if (tun == NULL) - return "uninitialized tun options"; + if (cfg == NULL) + return "uninitialized tun/tap options"; - if (FALSE == tun->persistent) + if (FALSE == cfg->persistent) return "Invalid/unsupported tun persistent setting (FALSE)"; - if (tun->owner == -1u) + if (cfg->owner == -1U) return "Invalid/unset tun owner UID"; - if (tun->group == -1u) + if (cfg->group == -1U) return "Invalid tun group GID"; return NULL; } -static inline gid_t -__ni_tun_normalize_group(gid_t group) -{ - return group == -1u ? 0 : group; -} - /* * Load tun configuration from sysfs */ int -ni_tun_parse_sysfs_attrs(const char *ifname, ni_tun_t *tun) +ni_tuntap_parse_sysfs_attrs(const char *ifname, ni_tuntap_t *cfg) { static const struct { const char *name; ni_bool_t nofail; /* don't fail, may be missed */ } attrs[] = { - { "owner", FALSE }, + { "owner", FALSE }, { "group", FALSE }, - { NULL, FALSE }, + { NULL, FALSE }, }; - const char *err = NULL; - __ni_tun_init(tun); + __ni_tuntap_init(cfg); - if (ni_sysfs_netif_get_uint(ifname, attrs[0].name, &tun->owner) < 0) { + if (ni_sysfs_netif_get_uint(ifname, attrs[0].name, &cfg->owner) < 0) { if (!attrs[0].nofail) return -1; } - if (ni_sysfs_netif_get_uint(ifname, attrs[1].name, &tun->group) < 0) { + if (ni_sysfs_netif_get_uint(ifname, attrs[1].name, &cfg->group) < 0) { if (!attrs[1].nofail) return -1; } - /* When group is unset (-1), should be normalized to GID=0 */ - tun->group = __ni_tun_normalize_group(tun->group); - - if ((err = ni_tun_validate(tun))) { - ni_error("%s: %s", ifname, err); - return -1; - } - return 0; }