[PATCH 6/6] VLAN: create NMDeviceVLAN and activate it



When NetworkManager receives the message that a VLAN device is created in kernel,
it should create corresponding NMDeviceVLAN object, and then activate it.

Before activating a VLAN device, we should make sure that the underlying
physical ethernet device is up.
For example, before activating eth0.100, we should make sure that eth0 is up.
NetworkManager calls g_udev_client_query_by_subsystem() to get the device
list, and then activates each devices on that device list.
And luckily I found that the physical ethernet device is prior to VLAN device
on that device list, so there is nothing to do to make sure the activating
sequence between a VLAN device and its underlying physical ethernet device.

Signed-off-by: Weiping Pan <wpan redhat com>
---
 src/nm-system.c       |   31 ++++++++++++++
 src/nm-system.h       |    1 +
 src/nm-udev-manager.c |  105 ++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 136 insertions(+), 1 deletions(-)

diff --git a/src/nm-system.c b/src/nm-system.c
index 8696000..62d0961 100644
--- a/src/nm-system.c
+++ b/src/nm-system.c
@@ -1436,3 +1436,34 @@ free_cache:
 	nl_cache_free(cache);
 	return FALSE;
 }
+
+/**
+ * nm_system_get_link_type:
+ * @name: name of link
+ *
+ * Lookup virtual link type. The returned string is allocated and needs
+ * to be freed after usage.
+ *
+ * Returns: Name of virtual link type or NULL if not a virtual link.
+ **/
+char *
+nm_system_get_link_type(const char *name)
+{
+	struct rtnl_link *result;
+	struct nl_sock *nlh;
+	char *type;
+
+	nlh = nm_netlink_get_default_handle ();
+	if (!nlh)
+		return NULL;
+
+	if (rtnl_link_get_kernel (nlh, 0, name, &result) < 0)
+		return NULL;
+
+	if ((type = rtnl_link_get_type (result)))
+		type = g_strdup(type);
+
+	rtnl_link_put (result);
+
+	return type;
+}
diff --git a/src/nm-system.h b/src/nm-system.h
index 93f942c..2f0e65c 100644
--- a/src/nm-system.h
+++ b/src/nm-system.h
@@ -92,4 +92,5 @@ gboolean		nm_system_iface_set_mac                 (int ifindex, const struct eth
 gboolean		nm_system_add_vlan_device(NMSettingVLAN *setting);
 gboolean		nm_system_del_vlan_device(NMSettingVLAN *setting);
 
+char *			nm_system_get_link_type		(const char *name);
 #endif
diff --git a/src/nm-udev-manager.c b/src/nm-udev-manager.c
index e8c6b82..3634423 100644
--- a/src/nm-udev-manager.c
+++ b/src/nm-udev-manager.c
@@ -42,6 +42,12 @@
 #include "nm-device-wimax.h"
 #endif
 
+#include "nm-system.h"
+#include "nm-device-vlan.h"
+#include "nm-setting-vlan.h"
+#include "nm-netlink-monitor.h"
+#include <netlink/route/link/vlan.h>
+
 typedef struct {
 	GUdevClient *client;
 
@@ -388,6 +394,90 @@ is_wimax (const char *driver)
 	return g_strcmp0 (driver, "i2400m_usb") == 0;
 }
 
+static gboolean
+is_vlan (const char *name)
+{
+	gboolean ret = FALSE;
+	struct rtnl_link *search_link = NULL;
+	struct nl_sock *nlh = NULL;
+	struct nl_cache *cache = NULL;
+
+	nlh = nm_netlink_get_default_handle();
+	if (!nlh)
+		return FALSE;
+
+	if (rtnl_link_alloc_cache(nlh, &cache) < 0)
+		return FALSE;
+
+	if (!cache)
+		return FALSE;
+
+	search_link = rtnl_link_get_by_name(cache, name);
+	if (!search_link)
+		goto free_cache;
+
+	if (rtnl_link_is_vlan(search_link))
+		ret = TRUE;
+
+	rtnl_link_put(search_link);
+
+	return ret;
+
+free_cache:
+	nl_cache_free(cache);
+	return FALSE;
+}
+
+static NMSettingVLAN *
+create_nm_settingvlan_from_gudev_device (GUdevDevice *device)
+{
+	struct rtnl_link *search_link = NULL;
+	struct nl_sock *nlh = NULL;
+	struct nl_cache *cache = NULL;
+
+	const char *interface_name;
+	int vlan_id;
+	int vlan_flags;
+
+	NMSettingVLAN * s_vlan = NULL;
+
+	interface_name = g_udev_device_get_name (device);
+	g_assert (interface_name);
+	nlh = nm_netlink_get_default_handle();
+	if (!nlh)
+		return FALSE;
+
+	if (rtnl_link_alloc_cache(nlh, &cache) < 0)
+		return FALSE;
+
+	if (!cache)
+		return FALSE;
+
+	search_link = rtnl_link_get_by_name(cache, interface_name);
+	if (!search_link)
+		goto free_cache;
+
+	if (rtnl_link_is_vlan(search_link)) {
+		vlan_id = rtnl_link_vlan_get_id(search_link);
+		vlan_flags = rtnl_link_vlan_get_flags(search_link);
+		// TODO
+		// ingress and egress priority mapping
+	}
+
+	rtnl_link_put(search_link);
+
+	s_vlan = NM_SETTING_VLAN(nm_setting_vlan_new());
+	g_object_set(s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, interface_name, NULL);
+	g_object_set(s_vlan, NM_SETTING_VLAN_VLAN_ID, vlan_id, NULL);
+	g_object_set(s_vlan, NM_SETTING_VLAN_VLAN_FLAGS, vlan_flags, NULL);
+
+	return s_vlan;
+
+free_cache:
+	nl_cache_free(cache);
+	return NULL;
+}
+
 static GObject *
 device_creator (NMUdevManager *manager,
                 GUdevDevice *udev_device,
@@ -430,7 +520,15 @@ device_creator (NMUdevManager *manager,
 	}
 
 	if (!driver) {
-		if (g_str_has_prefix (ifname, "easytether")) {
+		char *type = NULL;
+
+		type = nm_system_get_link_type (ifname);
+		if (type) {
+			if (g_strcmp0 (type, "vlan") == 0)
+				driver = "8021q";
+
+			g_free(type);
+		} else if (g_str_has_prefix (ifname, "easytether")) {
 			driver = "easytether";
 		} else {
 			nm_log_warn (LOGD_HW, "%s: couldn't determine device driver; ignoring...", path);
@@ -452,6 +550,11 @@ device_creator (NMUdevManager *manager,
 #if WITH_WIMAX
 		device = (GObject *) nm_device_wimax_new (path, ifname, driver);
 #endif
+	} else if (is_vlan(ifname)) {
+		NMSettingVLAN *s_vlan = NULL;
+		s_vlan = (NMSettingVLAN *)create_nm_settingvlan_from_gudev_device(udev_device);
+		device = (GObject *) nm_device_vlan_new(s_vlan);
+		g_object_unref(s_vlan);
 	} else
 		device = (GObject *) nm_device_ethernet_new (path, ifname, driver);
 
-- 
1.7.4.4



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]