From b636ea86b1c0a28b77eda311c84d3b2417cad22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0imerda?= Date: Wed, 27 Mar 2013 22:53:55 +0100 Subject: [PATCH] platform: link features (carrier-detect and vlans) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks to Jiří Pírko for help with ethtool features. --- src/platform/nm-fake-platform.c | 35 +++++++++++++++++ src/platform/nm-linux-platform.c | 66 ++++++++++++++++++++++++++++++++ src/platform/nm-platform.c | 18 +++++++++ src/platform/nm-platform.h | 6 +++ src/platform/tests/dump.c | 5 +++ src/platform/tests/test-link.c | 12 ++++++ 6 files changed, 142 insertions(+) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 4c20b5628c..231886c0bb 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -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; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 7aa74f32d3..b1a35c5f69 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -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; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 9996437ab5..c8df2e3489 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -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 diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index d5a1e64204..32461e4a5f 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -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); diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c index 42a43abcf2..4f4aa127eb 100644 --- a/src/platform/tests/dump.c +++ b/src/platform/tests/dump.c @@ -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); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index ca869035b0..be1e7cc6ed 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -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 ();