platform: link features (carrier-detect and vlans)

Thanks to Jiří Pírko for help with ethtool features.
This commit is contained in:
Pavel Šimerda 2013-03-27 22:53:55 +01:00
parent 3071cc6511
commit b636ea86b1
6 changed files with 142 additions and 0 deletions

View file

@ -268,6 +268,38 @@ link_uses_arp (NMPlatform *platform, int ifindex)
return device ? device->arp : FALSE;
}
static gboolean
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
{
NMPlatformLink *device = link_get (platform, ifindex);
if (!device)
return FALSE;
switch (device->type) {
case NM_LINK_TYPE_DUMMY:
return FALSE;
default:
return TRUE;
}
}
static gboolean
link_supports_vlans (NMPlatform *platform, int ifindex)
{
NMPlatformLink *device = link_get (platform, ifindex);
if (!device)
return FALSE;
switch (device->type) {
case NM_LINK_TYPE_LOOPBACK:
return FALSE;
default:
return TRUE;
}
}
/******************************************************************/
static GArray *
@ -698,6 +730,9 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->link_is_connected = link_is_connected;
platform_class->link_uses_arp = link_uses_arp;
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
platform_class->link_supports_vlans = link_supports_vlans;
platform_class->ip4_address_get_all = ip4_address_get_all;
platform_class->ip6_address_get_all = ip6_address_get_all;
platform_class->ip4_address_add = ip4_address_add;

View file

@ -25,6 +25,9 @@
#include <netinet/icmp6.h>
#include <netinet/in.h>
#include <linux/if_arp.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <linux/ethtool.h>
#include <netlink/netlink.h>
#include <netlink/object.h>
#include <netlink/cache.h>
@ -816,6 +819,66 @@ link_set_noarp (NMPlatform *platform, int ifindex)
return link_change_flags (platform, ifindex, IFF_NOARP, TRUE);
}
static gboolean
ethtool_get (const char *name, gpointer edata)
{
struct ifreq ifr;
int fd;
memset (&ifr, 0, sizeof (ifr));
strncpy (ifr.ifr_name, name, IFNAMSIZ);
ifr.ifr_data = edata;
fd = socket (PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
error ("ethtool: Could not open socket.");
return FALSE;
}
if (ioctl (fd, SIOCETHTOOL, &ifr) < 0) {
debug ("ethtool: Request failed: %s", strerror (errno));
close (fd);
return FALSE;
}
close (fd);
return TRUE;
}
static gboolean
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
{
const char *name = nm_platform_link_get_name (ifindex);
struct ethtool_cmd edata = { .cmd = ETHTOOL_GLINK };
/* We ignore the result and only return FALSE on error */
return name && ethtool_get (name, &edata);
}
#define NETIF_F_VLAN_CHALLENGED (1 << 10)
static gboolean
link_supports_vlans (NMPlatform *platform, int ifindex)
{
auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
const char *name = nm_platform_link_get_name (ifindex);
struct {
struct ethtool_gfeatures features;
struct ethtool_get_features_block features_block;
} edata = { .features = { .cmd = ETHTOOL_GFEATURES, .size = 1 } };
/* Only ARPHDR_ETHER links can possibly support VLANs. Thanks to Dan Winship
* for pointing this out.
*/
if (!rtnllink || rtnl_link_get_arptype (rtnllink) != ARPHRD_ETHER)
return FALSE;
if (!name || !ethtool_get (name, &edata))
return FALSE;
return !(edata.features.features[0].active & NETIF_F_VLAN_CHALLENGED);
}
/******************************************************************/
static int
@ -1274,6 +1337,9 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_is_connected = link_is_connected;
platform_class->link_uses_arp = link_uses_arp;
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
platform_class->link_supports_vlans = link_supports_vlans;
platform_class->ip4_address_get_all = ip4_address_get_all;
platform_class->ip6_address_get_all = ip6_address_get_all;
platform_class->ip4_address_add = ip4_address_add;

View file

@ -412,6 +412,24 @@ nm_platform_link_uses_arp (int ifindex)
return klass->link_uses_arp (platform, ifindex);
}
gboolean
nm_platform_link_supports_carrier_detect (int ifindex)
{
g_return_val_if_fail (ifindex >= 0, FALSE);
g_return_val_if_fail (klass->link_supports_carrier_detect, FALSE);
return klass->link_supports_carrier_detect (platform, ifindex);
}
gboolean
nm_platform_link_supports_vlans (int ifindex)
{
g_return_val_if_fail (ifindex >= 0, FALSE);
g_return_val_if_fail (klass->link_supports_vlans, FALSE);
return klass->link_supports_vlans (platform, ifindex);
}
/**
* nm_platform_link_set_up:
* @ifindex: Interface index

View file

@ -136,6 +136,9 @@ typedef struct {
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
gboolean (*link_uses_arp) (NMPlatform *, int ifindex);
gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
gboolean (*link_supports_vlans) (NMPlatform *, int ifindex);
GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex);
GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex);
gboolean (*ip4_address_add) (NMPlatform *, int ifindex, in_addr_t address, int plen);
@ -228,6 +231,9 @@ gboolean nm_platform_link_is_up (int ifindex);
gboolean nm_platform_link_is_connected (int ifindex);
gboolean nm_platform_link_uses_arp (int ifindex);
gboolean nm_platform_link_supports_carrier_detect (int ifindex);
gboolean nm_platform_link_supports_vlans (int ifindex);
GArray *nm_platform_ip4_address_get_all (int ifindex);
GArray *nm_platform_ip6_address_get_all (int ifindex);
gboolean nm_platform_ip4_address_add (int ifindex, in_addr_t address, int plen);

View file

@ -48,6 +48,11 @@ dump_interface (NMPlatformLink *link)
printf (" noarp");
printf ("\n");
if (nm_platform_link_supports_carrier_detect (link->ifindex))
printf (" feature carrier-detect\n");
if (nm_platform_link_supports_vlans (link->ifindex))
printf (" feature vlans\n");
ip4_addresses = nm_platform_ip4_address_get_all (link->ifindex);
ip6_addresses = nm_platform_ip6_address_get_all (link->ifindex);

View file

@ -78,6 +78,11 @@ test_bogus(void)
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_supports_carrier_detect (BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
g_assert (!nm_platform_link_supports_vlans (BOGUS_IFINDEX));
error (NM_PLATFORM_ERROR_NOT_FOUND);
}
static void
@ -87,6 +92,9 @@ test_loopback (void)
g_assert (nm_platform_link_get_type (LO_INDEX) == NM_LINK_TYPE_LOOPBACK);
g_assert (nm_platform_link_get_ifindex (LO_NAME) == LO_INDEX);
g_assert (!g_strcmp0 (nm_platform_link_get_name (LO_INDEX), LO_NAME));
g_assert (nm_platform_link_supports_carrier_detect (LO_INDEX));
g_assert (!nm_platform_link_supports_vlans (LO_INDEX));
}
static void
@ -138,6 +146,10 @@ test_internal (void)
g_assert (!nm_platform_link_uses_arp (ifindex));
accept_signal (link_changed);
/* Features */
g_assert (!nm_platform_link_supports_carrier_detect (ifindex));
g_assert (nm_platform_link_supports_vlans (ifindex));
/* Delete device */
g_assert (nm_platform_link_delete (ifindex));
no_error ();