platform: link features (carrier-detect and vlans)
Thanks to Jiří Pírko for help with ethtool features.
This commit is contained in:
@@ -268,6 +268,38 @@ link_uses_arp (NMPlatform *platform, int ifindex)
|
|||||||
return device ? device->arp : FALSE;
|
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 *
|
static GArray *
|
||||||
@@ -698,6 +730,9 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
|||||||
platform_class->link_is_connected = link_is_connected;
|
platform_class->link_is_connected = link_is_connected;
|
||||||
platform_class->link_uses_arp = link_uses_arp;
|
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->ip4_address_get_all = ip4_address_get_all;
|
||||||
platform_class->ip6_address_get_all = ip6_address_get_all;
|
platform_class->ip6_address_get_all = ip6_address_get_all;
|
||||||
platform_class->ip4_address_add = ip4_address_add;
|
platform_class->ip4_address_add = ip4_address_add;
|
||||||
|
@@ -25,6 +25,9 @@
|
|||||||
#include <netinet/icmp6.h>
|
#include <netinet/icmp6.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <linux/if_arp.h>
|
#include <linux/if_arp.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/sockios.h>
|
||||||
|
#include <linux/ethtool.h>
|
||||||
#include <netlink/netlink.h>
|
#include <netlink/netlink.h>
|
||||||
#include <netlink/object.h>
|
#include <netlink/object.h>
|
||||||
#include <netlink/cache.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);
|
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
|
static int
|
||||||
@@ -1274,6 +1337,9 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||||||
platform_class->link_is_connected = link_is_connected;
|
platform_class->link_is_connected = link_is_connected;
|
||||||
platform_class->link_uses_arp = link_uses_arp;
|
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->ip4_address_get_all = ip4_address_get_all;
|
||||||
platform_class->ip6_address_get_all = ip6_address_get_all;
|
platform_class->ip6_address_get_all = ip6_address_get_all;
|
||||||
platform_class->ip4_address_add = ip4_address_add;
|
platform_class->ip4_address_add = ip4_address_add;
|
||||||
|
@@ -412,6 +412,24 @@ nm_platform_link_uses_arp (int ifindex)
|
|||||||
return klass->link_uses_arp (platform, 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:
|
* nm_platform_link_set_up:
|
||||||
* @ifindex: Interface index
|
* @ifindex: Interface index
|
||||||
|
@@ -136,6 +136,9 @@ typedef struct {
|
|||||||
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
|
gboolean (*link_is_connected) (NMPlatform *, int ifindex);
|
||||||
gboolean (*link_uses_arp) (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 * (*ip4_address_get_all) (NMPlatform *, int ifindex);
|
||||||
GArray * (*ip6_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);
|
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_is_connected (int ifindex);
|
||||||
gboolean nm_platform_link_uses_arp (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_ip4_address_get_all (int ifindex);
|
||||||
GArray *nm_platform_ip6_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);
|
gboolean nm_platform_ip4_address_add (int ifindex, in_addr_t address, int plen);
|
||||||
|
@@ -48,6 +48,11 @@ dump_interface (NMPlatformLink *link)
|
|||||||
printf (" noarp");
|
printf (" noarp");
|
||||||
printf ("\n");
|
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);
|
ip4_addresses = nm_platform_ip4_address_get_all (link->ifindex);
|
||||||
ip6_addresses = nm_platform_ip6_address_get_all (link->ifindex);
|
ip6_addresses = nm_platform_ip6_address_get_all (link->ifindex);
|
||||||
|
|
||||||
|
@@ -78,6 +78,11 @@ test_bogus(void)
|
|||||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||||
g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX));
|
g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX));
|
||||||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
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
|
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_type (LO_INDEX) == NM_LINK_TYPE_LOOPBACK);
|
||||||
g_assert (nm_platform_link_get_ifindex (LO_NAME) == LO_INDEX);
|
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 (!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
|
static void
|
||||||
@@ -138,6 +146,10 @@ test_internal (void)
|
|||||||
g_assert (!nm_platform_link_uses_arp (ifindex));
|
g_assert (!nm_platform_link_uses_arp (ifindex));
|
||||||
accept_signal (link_changed);
|
accept_signal (link_changed);
|
||||||
|
|
||||||
|
/* Features */
|
||||||
|
g_assert (!nm_platform_link_supports_carrier_detect (ifindex));
|
||||||
|
g_assert (nm_platform_link_supports_vlans (ifindex));
|
||||||
|
|
||||||
/* Delete device */
|
/* Delete device */
|
||||||
g_assert (nm_platform_link_delete (ifindex));
|
g_assert (nm_platform_link_delete (ifindex));
|
||||||
no_error ();
|
no_error ();
|
||||||
|
Reference in New Issue
Block a user