summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Šimerda <psimerda@redhat.com>2013-03-27 22:53:55 +0100
committerPavel Šimerda <psimerda@redhat.com>2013-04-10 16:40:58 +0200
commitb636ea86b1c0a28b77eda311c84d3b2417cad22e (patch)
tree24b436fc93e2796b17073c1e299de551d0f33ea4
parent3071cc6511afcc6256605b1031acad2793323f6d (diff)
downloadNetworkManager-b636ea86b1c0a28b77eda311c84d3b2417cad22e.tar.gz
platform: link features (carrier-detect and vlans)
Thanks to Jiří Pírko for help with ethtool features.
-rw-r--r--src/platform/nm-fake-platform.c35
-rw-r--r--src/platform/nm-linux-platform.c66
-rw-r--r--src/platform/nm-platform.c18
-rw-r--r--src/platform/nm-platform.h6
-rw-r--r--src/platform/tests/dump.c5
-rw-r--r--src/platform/tests/test-link.c12
6 files changed, 142 insertions, 0 deletions
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 <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;
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 ();