We make use of libnl (>=3.2.1) to create/delete kernel vlan device, and it can set vlan id, vlan flags and ingress/egress priority mapping.
V3: 1 nm_netlink_iface_to_index() should use slave name V2: 1 use existing nm_netlink_iface_to_index() Signed-off-by: Weiping Pan <w...@redhat.com> --- src/nm-system.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/nm-system.h | 4 ++ 2 files changed, 156 insertions(+), 0 deletions(-) diff --git a/src/nm-system.c b/src/nm-system.c index 75d2c9f..c00106f 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -59,6 +59,7 @@ #include <netlink/netlink.h> #include <netlink/utils.h> #include <netlink/route/link.h> +#include <netlink/route/link/vlan.h> #ifdef HAVE_LIBNL3 #include <netlink/route/link/bonding.h> @@ -1529,3 +1530,154 @@ out: return res; } +static void ingress_priority_iterator (gpointer data, gpointer user_data) +{ + struct rtnl_link *new_link = user_data; + vlan_priority_map *item = data; + + g_return_if_fail (item != NULL); + g_return_if_fail (new_link != NULL); + + if ((item->from < 0) || (item->from > 7)) + return; + + rtnl_link_vlan_set_ingress_map (new_link, item->from, item->to); +} + +static void egress_priority_iterator(gpointer data, gpointer user_data) +{ + struct rtnl_link *new_link = user_data; + vlan_priority_map *item = data; + + g_return_if_fail (item != NULL); + g_return_if_fail (new_link != NULL); + + if ((item->to < 0) || (item->to > 7)) + return; + + rtnl_link_vlan_set_egress_map (new_link, item->from, item->to); +} + +/** + * nm_system_add_vlan_device: + * @setting: NMSettingVlan + * + * Add a VLAN device specified in @setting. + * + * Returns: %TRUE on success, or %FALSE + */ +gboolean +nm_system_add_vlan_device (NMSettingVlan *setting) +{ + int ret = 0; + int if_index = 0; + struct rtnl_link *new_link = NULL; + struct nl_sock *nlh = NULL; + const GSList *list = NULL; + + const char *interface_name = NULL; + const char *vlan_slave = NULL; + guint32 vlan_id = 0; + guint32 vlan_flags = 0; + + g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE); + + vlan_slave = nm_setting_vlan_get_slave (setting); + g_return_val_if_fail (vlan_slave != NULL, FALSE); + + vlan_id = nm_setting_vlan_get_id (setting); + g_return_val_if_fail (vlan_id != 0, FALSE); + g_return_val_if_fail (vlan_id < 4096, FALSE); + + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, FALSE); + + interface_name = nm_setting_vlan_get_interface_name (setting); + g_return_val_if_fail (interface_name != NULL, FALSE); + + if_index = nm_netlink_iface_to_index (vlan_slave); + g_return_val_if_fail (if_index > 0, FALSE); + + new_link = rtnl_link_alloc (); + g_return_val_if_fail (new_link != NULL, FALSE); + + ret = rtnl_link_set_type (new_link, "vlan"); + if (ret < 0) + goto free_new_link; + + rtnl_link_set_link (new_link, if_index); + rtnl_link_set_name (new_link, interface_name); + rtnl_link_vlan_set_id (new_link, vlan_id); + + vlan_flags = nm_setting_vlan_get_flags (setting); + if (vlan_flags) + rtnl_link_vlan_set_flags (new_link, vlan_flags); + + list = nm_setting_vlan_get_ingress_priority_map (setting); + if (list != NULL) + g_slist_foreach ((GSList *)list, (GFunc)ingress_priority_iterator, new_link); + + list = nm_setting_vlan_get_egress_priority_map (setting); + if (list != NULL) + g_slist_foreach((GSList *)list, (GFunc)egress_priority_iterator, new_link); + + ret = rtnl_link_add (nlh, new_link, NLM_F_CREATE); + if (ret < 0) + goto free_new_link; + + rtnl_link_put (new_link); + + return TRUE; + +free_new_link: + rtnl_link_put (new_link); + + return FALSE; +} + +/** + * nm_system_del_vlan_device: + * @setting: NMSettingVlan + * + * Delete a VLAN device specified in @setting. + * + * Returns: %TRUE on success, or %FALSE + */ +gboolean +nm_system_del_vlan_device (NMSettingVlan *setting) +{ + int ret = 0; + struct nl_sock *nlh = NULL; + struct nl_cache *cache = NULL; + struct rtnl_link *new_link = NULL; + const char *interface_name = NULL; + + interface_name = nm_setting_vlan_get_interface_name (setting); + g_return_val_if_fail (interface_name != NULL, FALSE); + + nlh = nm_netlink_get_default_handle (); + g_return_val_if_fail (nlh != NULL, FALSE); + + ret = rtnl_link_alloc_cache (nlh, &cache); + g_return_val_if_fail (ret == 0, FALSE); + g_return_val_if_fail (cache != NULL, FALSE); + + new_link = rtnl_link_get_by_name (cache, interface_name); + if (!new_link) + goto free_cache; + + ret = rtnl_link_delete (nlh, new_link); + if (ret < 0) + goto free_new_link; + + rtnl_link_put (new_link); + + return TRUE; + +free_new_link: + rtnl_link_put (new_link); + +free_cache: + nl_cache_free (cache); + return FALSE; +} diff --git a/src/nm-system.h b/src/nm-system.h index 34bfb86..03b1cad 100644 --- a/src/nm-system.h +++ b/src/nm-system.h @@ -31,6 +31,7 @@ #include "nm-device.h" #include "nm-ip4-config.h" #include "nm-setting-bond.h" +#include "nm-setting-vlan.h" /* Prototypes for system/distribution dependent functions, * implemented in the backend files in backends/ directory @@ -102,4 +103,7 @@ enum { int nm_system_get_iface_type (const char *name); +gboolean nm_system_add_vlan_device (NMSettingVlan *setting); +gboolean nm_system_del_vlan_device (NMSettingVlan *setting); + #endif -- 1.7.4.4 _______________________________________________ networkmanager-list mailing list networkmanager-list@gnome.org http://mail.gnome.org/mailman/listinfo/networkmanager-list