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 <[email protected]>
---
 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

_______________________________________________
networkmanager-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to