core: add compat function for determining interface type

libnl2 and earlier do not implement rtnl_link_get_kernel() and
thus we need compat code to determine whether an interface is
a bond or a VLAN.  Previously, the VLAN code would simply assert
and cause NM to exit when running with libnl2 or earlier because
the interface type could not be determined.
This commit is contained in:
Dan Williams 2012-08-02 20:51:23 -05:00
parent 54dd265001
commit 82f4fd6545
2 changed files with 70 additions and 3 deletions

View file

@ -636,7 +636,11 @@ nm_device_vlan_new (const char *udi, const char *iface, NMDevice *parent)
int vlan_id;
itype = nm_system_get_iface_type (ifindex, iface);
g_assert (itype == NM_IFACE_TYPE_VLAN);
if (itype != NM_IFACE_TYPE_VLAN) {
nm_log_err (LOGD_DEVICE, "(%s): failed to get VLAN interface type.", iface);
g_object_unref (device);
return NULL;
}
if (!nm_system_get_iface_vlan_info (ifindex, &parent_ifindex, &vlan_id)) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to get VLAN interface info.", iface);

View file

@ -15,7 +15,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2004 - 2010 Red Hat, Inc.
* Copyright (C) 2004 - 2012 Red Hat, Inc.
* Copyright (C) 2005 - 2008 Novell, Inc.
* Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi@fore.com>
* Copyright (C) January, 1998 Sergei Viznyuk <sv@phystech.com>
@ -44,6 +44,7 @@
#include <linux/if.h>
#include <linux/sockios.h>
#include <linux/if_bonding.h>
#include <linux/if_vlan.h>
#include "nm-system.h"
#include "nm-device.h"
@ -1733,6 +1734,63 @@ nm_system_iface_release (gint master_ifindex,
return TRUE;
}
/**
* nm_system_get_iface_type_compat:
* @ifindex: interface index
* @name: name of interface
*
* Lookup the type of an interface. At least one of @ifindex or @name must
* be provided.
*
* Returns: Interface type (NM_IFACE_TYPE_*) or NM_IFACE_TYPE_UNSPEC.
**/
static int
nm_system_compat_get_iface_type (int ifindex, const char *name)
{
int res = NM_IFACE_TYPE_UNSPEC;
char *ifname = NULL;
struct vlan_ioctl_args ifv;
struct ifreq ifr;
struct ifbond ifb;
int fd;
g_return_val_if_fail (ifindex > 0 || name, NM_IFACE_TYPE_UNSPEC);
if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
goto out;
}
if (!name) {
g_assert (ifindex > 0);
ifname = nm_netlink_index_to_iface (ifindex);
}
/* Check VLAN */
memset (&ifv, 0, sizeof (ifv));
ifv.cmd = GET_VLAN_VID_CMD;
strncpy (ifv.device1, ifname ? ifname : name, sizeof (ifv.device1) - 1);
if (ioctl (fd, SIOCGIFVLAN, &ifv) == 0) {
res = NM_IFACE_TYPE_VLAN;
goto out;
}
/* and bond */
memset (&ifr, 0, sizeof (ifr));
strncpy (ifr.ifr_name, ifname ? ifname : name, sizeof (ifr.ifr_name) - 1);
memset (&ifb, 0, sizeof (ifb));
ifr.ifr_data = (caddr_t) &ifb;
if (ioctl (fd, SIOCBONDINFOQUERY, &ifr) == 0) {
res = NM_IFACE_TYPE_BOND;
goto out;
}
out:
close (fd);
g_free (ifname);
return res;
}
/**
* nm_system_get_iface_type:
* @ifindex: interface index
@ -1750,6 +1808,7 @@ nm_system_get_iface_type (int ifindex, const char *name)
struct nl_sock *nlh;
char *type;
int res = NM_IFACE_TYPE_UNSPEC;
int err;
g_return_val_if_fail (ifindex > 0 || name, NM_IFACE_TYPE_UNSPEC);
@ -1758,8 +1817,12 @@ nm_system_get_iface_type (int ifindex, const char *name)
goto out;
/* Prefer interface indexes to names */
if (rtnl_link_get_kernel (nlh, ifindex, ifindex < 0 ? name : NULL, &result) < 0)
err = rtnl_link_get_kernel (nlh, ifindex, ifindex < 0 ? name : NULL, &result);
if (err < 0) {
if (err == -NLE_OPNOTSUPP)
res = nm_system_compat_get_iface_type (ifindex, name);
goto out;
}
type = rtnl_link_get_type (result);