From c1e53dbf7c1b53cb90e0c6c987b59cf89445704c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0imerda?= Date: Wed, 27 Mar 2013 22:23:24 +0100 Subject: [PATCH] platform: link state, carrier and arp --- src/platform/nm-fake-platform.c | 115 +++++++++++++++++++++++++++++ src/platform/nm-linux-platform.c | 104 ++++++++++++++++++++++++++ src/platform/nm-platform.c | 123 +++++++++++++++++++++++++++++++ src/platform/nm-platform.h | 19 +++++ src/platform/tests/dump.c | 8 ++ src/platform/tests/test-link.c | 63 ++++++++++++++++ 6 files changed, 432 insertions(+) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index b591918a9e..0899680ea4 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -57,6 +57,13 @@ link_init (NMPlatformLink *device, int ifindex, int type, const char *name) device->type = type; if (name) strcpy (device->name, name); + switch (device->type) { + case NM_LINK_TYPE_DUMMY: + device->arp = FALSE; + break; + default: + device->arp = TRUE; + } } static NMPlatformLink * @@ -157,6 +164,106 @@ link_get_type (NMPlatform *platform, int ifindex) return device ? device->type : NM_LINK_TYPE_NONE; } +static void +link_changed (NMPlatform *platform, NMPlatformLink *device) +{ + g_signal_emit_by_name (platform, "link-changed", device); +} + +static gboolean +link_set_up (NMPlatform *platform, int ifindex) +{ + NMPlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->up = TRUE; + switch (device->type) { + case NM_LINK_TYPE_GENERIC: + case NM_LINK_TYPE_DUMMY: + device->connected = TRUE; + break; + default: + device->connected = FALSE; + g_error ("Unexpected device type: %d", device->type); + } + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_set_down (NMPlatform *platform, int ifindex) +{ + NMPlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->up = FALSE; + device->connected = FALSE; + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_set_arp (NMPlatform *platform, int ifindex) +{ + NMPlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->arp = TRUE; + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_set_noarp (NMPlatform *platform, int ifindex) +{ + NMPlatformLink *device = link_get (platform, ifindex); + + if (!device) + return FALSE; + + device->arp = FALSE; + + link_changed (platform, device); + + return TRUE; +} + +static gboolean +link_is_up (NMPlatform *platform, int ifindex) +{ + NMPlatformLink *device = link_get (platform, ifindex); + + return device ? device->up : FALSE; +} + +static gboolean +link_is_connected (NMPlatform *platform, int ifindex) +{ + NMPlatformLink *device = link_get (platform, ifindex); + + return device ? device->connected : FALSE; +} + +static gboolean +link_uses_arp (NMPlatform *platform, int ifindex) +{ + NMPlatformLink *device = link_get (platform, ifindex); + + return device ? device->arp : FALSE; +} + /******************************************************************/ static void @@ -213,4 +320,12 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_get_ifindex = link_get_ifindex; platform_class->link_get_name = link_get_name; platform_class->link_get_type = link_get_type; + + platform_class->link_set_up = link_set_up; + platform_class->link_set_down = link_set_down; + platform_class->link_set_arp = link_set_arp; + platform_class->link_set_noarp = link_set_noarp; + platform_class->link_is_up = link_is_up; + platform_class->link_is_connected = link_is_connected; + platform_class->link_uses_arp = link_uses_arp; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 8df473578c..b3fab26516 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -240,6 +240,9 @@ link_init (NMPlatformLink *info, struct rtnl_link *rtnllink) info->ifindex = rtnl_link_get_ifindex (rtnllink); strcpy (info->name, rtnl_link_get_name (rtnllink)); info->type = link_extract_type (rtnllink); + info->up = !!(rtnl_link_get_flags (rtnllink) & IFF_UP); + info->connected = !!(rtnl_link_get_flags (rtnllink) & IFF_LOWER_UP); + info->arp = !(rtnl_link_get_flags (rtnllink) & IFF_NOARP); } /******************************************************************/ @@ -502,6 +505,24 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type) return add_object (platform, build_rtnl_link (0, name, type)); } +static gboolean +link_change (NMPlatform *platform, int ifindex, struct rtnl_link *change) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *orig; + + orig = rtnl_link_get (priv->link_cache, ifindex); + + if (!orig) { + debug ("link not found: %d", ifindex); + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + return FALSE; + } + + return refresh_object (platform, (struct nl_object *) orig, + rtnl_link_change (priv->nlh, orig, change, 0)); +} + static gboolean link_delete (NMPlatform *platform, int ifindex) { @@ -544,6 +565,81 @@ link_get_type (NMPlatform *platform, int ifindex) return link_extract_type (rtnllink); } +static guint32 +link_get_flags (NMPlatform *platform, int ifindex) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *rtnllink; + + rtnllink = rtnl_link_get (priv->link_cache, ifindex); + + if (!rtnllink) { + debug ("link not found: %d", ifindex); + platform->error = NM_PLATFORM_ERROR_NOT_FOUND; + return IFF_NOARP; + } + + return rtnl_link_get_flags (rtnllink); +} + +static gboolean +link_is_up (NMPlatform *platform, int ifindex) +{ + return !!(link_get_flags (platform, ifindex) & IFF_UP); +} + +static gboolean +link_is_connected (NMPlatform *platform, int ifindex) +{ + return !!(link_get_flags (platform, ifindex) & IFF_LOWER_UP); +} + +static gboolean +link_uses_arp (NMPlatform *platform, int ifindex) +{ + return !(link_get_flags (platform, ifindex) & IFF_NOARP); +} + +static gboolean +link_change_flags (NMPlatform *platform, int ifindex, unsigned int flags, gboolean value) +{ + auto_nl_object struct rtnl_link *change; + + change = rtnl_link_alloc (); + g_return_val_if_fail (change != NULL, FALSE); + + if (value) + rtnl_link_set_flags (change, flags); + else + rtnl_link_unset_flags (change, flags); + + return link_change (platform, ifindex, change); +} + +static gboolean +link_set_up (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_UP, TRUE); +} + +static gboolean +link_set_down (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_UP, FALSE); +} + +static gboolean +link_set_arp (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_NOARP, FALSE); +} + +static gboolean +link_set_noarp (NMPlatform *platform, int ifindex) +{ + return link_change_flags (platform, ifindex, IFF_NOARP, TRUE); +} + /******************************************************************/ #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) @@ -698,4 +794,12 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_get_ifindex = link_get_ifindex; platform_class->link_get_name = link_get_name; platform_class->link_get_type = link_get_type; + + platform_class->link_set_up = link_set_up; + platform_class->link_set_down = link_set_down; + platform_class->link_set_arp = link_set_arp; + platform_class->link_set_noarp = link_set_noarp; + platform_class->link_is_up = link_is_up; + platform_class->link_is_connected = link_is_connected; + platform_class->link_uses_arp = link_uses_arp; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index b257f010f5..b2ffeac0f8 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -348,6 +348,129 @@ nm_platform_link_get_type (int ifindex) return klass->link_get_type (platform, ifindex); } +/** + * nm_platform_link_is_up: + * @ifindex: Interface index + * + * Check if the interface is up. + */ +gboolean +nm_platform_link_is_up (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_is_up, FALSE); + + return klass->link_is_up (platform, ifindex); +} + +/** + * nm_platform_link_is_connected: + * @ifindex: Interface index + * + * Check if the interface is connected. + */ +gboolean +nm_platform_link_is_connected (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_is_connected, FALSE); + + return klass->link_is_connected (platform, ifindex); +} + +/** + * nm_platform_link_uses_arp: + * @ifindex: Interface index + * + * Check if the interface is configured to use ARP. + */ +gboolean +nm_platform_link_uses_arp (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_uses_arp, FALSE); + + return klass->link_uses_arp (platform, ifindex); +} + +/** + * nm_platform_link_set_up: + * @ifindex: Interface index + * + * Bring the interface up. + */ +gboolean +nm_platform_link_set_up (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (klass->link_set_up, FALSE); + + debug ("link: setting up '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_up (platform, ifindex); +} + +/** + * nm_platform_link_set_down: + * @ifindex: Interface index + * + * Take the interface down. + */ +gboolean +nm_platform_link_set_down (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (klass->link_set_down, FALSE); + + debug ("link: setting down '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_down (platform, ifindex); +} + +/** + * nm_platform_link_set_arp: + * @ifindex: Interface index + * + * Enable ARP on the interface. + */ +gboolean +nm_platform_link_set_arp (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_set_arp, FALSE); + + debug ("link: setting arp '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_arp (platform, ifindex); +} + +/** + * nm_platform_link_set_noarp: + * @ifindex: Interface index + * + * Disable ARP on the interface. + */ +gboolean +nm_platform_link_set_noarp (int ifindex) +{ + reset_error (); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_set_noarp, FALSE); + + debug ("link: setting noarp '%s' (%d)", nm_platform_link_get_name (ifindex), ifindex); + return klass->link_set_noarp (platform, ifindex); +} + /******************************************************************/ static void diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index aeb7ab611b..3ef02c609a 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -47,6 +47,9 @@ typedef struct { int ifindex; char name[IFNAMSIZ]; NMLinkType type; + gboolean up; + gboolean connected; + gboolean arp; } NMPlatformLink; /******************************************************************/ @@ -96,6 +99,14 @@ typedef struct { int (*link_get_ifindex) (NMPlatform *, const char *name); const char *(*link_get_name) (NMPlatform *, int ifindex); NMLinkType (*link_get_type) (NMPlatform *, int ifindex); + + gboolean (*link_set_up) (NMPlatform *, int ifindex); + gboolean (*link_set_down) (NMPlatform *, int ifindex); + gboolean (*link_set_arp) (NMPlatform *, int ifindex); + gboolean (*link_set_noarp) (NMPlatform *, int ifindex); + gboolean (*link_is_up) (NMPlatform *, int ifindex); + gboolean (*link_is_connected) (NMPlatform *, int ifindex); + gboolean (*link_uses_arp) (NMPlatform *, int ifindex); } NMPlatformClass; /* NMPlatform signals @@ -145,4 +156,12 @@ int nm_platform_link_get_ifindex (const char *name); const char *nm_platform_link_get_name (int ifindex); NMLinkType nm_platform_link_get_type (int ifindex); +gboolean nm_platform_link_set_up (int ifindex); +gboolean nm_platform_link_set_down (int ifindex); +gboolean nm_platform_link_set_arp (int ifindex); +gboolean nm_platform_link_set_noarp (int ifindex); +gboolean nm_platform_link_is_up (int ifindex); +gboolean nm_platform_link_is_connected (int ifindex); +gboolean nm_platform_link_uses_arp (int ifindex); + #endif /* NM_PLATFORM_H */ diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c index 347b5e6a6a..7a9cade304 100644 --- a/src/platform/tests/dump.c +++ b/src/platform/tests/dump.c @@ -23,7 +23,15 @@ type_to_string (NMLinkType type) static void dump_interface (NMPlatformLink *link) { + g_assert (link->up || !link->connected); + printf ("%d: %s: %s", link->ifindex, link->name, type_to_string (link->type)); + if (link->up) + printf (" %s", link->connected ? "CONNECTED" : "DISCONNECTED"); + else + printf (" DOWN"); + if (!link->arp) + printf (" noarp"); printf ("\n"); } diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index de42ecc7e6..ca869035b0 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -63,6 +63,21 @@ test_bogus(void) error (NM_PLATFORM_ERROR_NOT_FOUND); g_assert (!nm_platform_link_get_type (BOGUS_IFINDEX)); error (NM_PLATFORM_ERROR_NOT_FOUND); + + g_assert (!nm_platform_link_set_up (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_set_down (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_set_arp (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_set_noarp (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_is_up (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_is_connected (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); + g_assert (!nm_platform_link_uses_arp (BOGUS_IFINDEX)); + error (NM_PLATFORM_ERROR_NOT_FOUND); } static void @@ -102,6 +117,27 @@ test_internal (void) g_assert (!g_strcmp0 (nm_platform_link_get_name (ifindex), DEVICE_NAME)); g_assert (nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_DUMMY); + /* Up/connected */ + g_assert (!nm_platform_link_is_up (ifindex)); no_error (); + g_assert (!nm_platform_link_is_connected (ifindex)); no_error (); + g_assert (nm_platform_link_set_up (ifindex)); no_error (); + g_assert (nm_platform_link_is_up (ifindex)); no_error (); + g_assert (nm_platform_link_is_connected (ifindex)); no_error (); + accept_signal (link_changed); + g_assert (nm_platform_link_set_down (ifindex)); no_error (); + g_assert (!nm_platform_link_is_up (ifindex)); no_error (); + g_assert (!nm_platform_link_is_connected (ifindex)); no_error (); + accept_signal (link_changed); + + /* arp/noarp */ + g_assert (!nm_platform_link_uses_arp (ifindex)); + g_assert (nm_platform_link_set_arp (ifindex)); + g_assert (nm_platform_link_uses_arp (ifindex)); + accept_signal (link_changed); + g_assert (nm_platform_link_set_noarp (ifindex)); + g_assert (!nm_platform_link_uses_arp (ifindex)); + accept_signal (link_changed); + /* Delete device */ g_assert (nm_platform_link_delete (ifindex)); no_error (); @@ -146,6 +182,33 @@ test_external (void) g_assert (!g_strcmp0 (nm_platform_link_get_name (ifindex), DEVICE_NAME)); g_assert (nm_platform_link_get_type (ifindex) == NM_LINK_TYPE_DUMMY); + /* Up/connected/arp */ + g_assert (!nm_platform_link_is_up (ifindex)); + g_assert (!nm_platform_link_is_connected (ifindex)); + g_assert (!nm_platform_link_uses_arp (ifindex)); + run_command ("ip link set %s up", DEVICE_NAME); + wait_signal (link_changed); + g_assert (nm_platform_link_is_up (ifindex)); + g_assert (nm_platform_link_is_connected (ifindex)); + run_command ("ip link set %s down", DEVICE_NAME); + wait_signal (link_changed); + g_assert (!nm_platform_link_is_up (ifindex)); + g_assert (!nm_platform_link_is_connected (ifindex)); + /* This test doesn't trigger a netlink event at least on + * 3.8.2-206.fc18.x86_64. Disabling the waiting and checking code + * because of that. + */ + run_command ("ip link set %s arp on", DEVICE_NAME); +#if 0 + wait_signal (link_changed); + g_assert (nm_platform_link_uses_arp (ifindex)); +#endif + run_command ("ip link set %s arp off", DEVICE_NAME); +#if 0 + wait_signal (link_changed); + g_assert (!nm_platform_link_uses_arp (ifindex)); +#endif + run_command ("ip link del %s", DEVICE_NAME); wait_signal (link_removed); g_assert (!nm_platform_link_exists (DEVICE_NAME));