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
