On 11/16/2011 01:43 PM, Dan Williams wrote:
On Fri, 2011-10-21 at 09:52 +0800, Weiping Pan wrote: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.Signed-off-by: Weiping Pan<[email protected]> --- src/nm-system.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/nm-system.h | 3 + 2 files changed, 237 insertions(+), 0 deletions(-) diff --git a/src/nm-system.c b/src/nm-system.c index 62ab8b9..8696000 100644 --- a/src/nm-system.c +++ b/src/nm-system.c @@ -56,6 +56,7 @@ #include<netlink/netlink.h> #include<netlink/utils.h> #include<netlink/route/link.h> +#include<netlink/route/link/vlan.h> static void nm_system_device_set_priority (int ifindex, NMIP4Config *config, @@ -1202,3 +1203,236 @@ nm_system_device_set_priority (int ifindex, rtnl_route_put (found); } } + +static void priority_parser(GHashTable *table, char *str, const char *delim, char *subdelim) +{ + char *str1, *str2, *token, *key = NULL, *value = NULL; + char *saveptr1, *saveptr2; + int j; + + if (!table) + return; + + for (j = 1, str1 = str; ; j++, str1 = NULL) { + int i; + token = strtok_r(str1, delim,&saveptr1); + if (token == NULL) + break; + + i = 0; + for (str2 = token; ; str2 = NULL) { + if (i == 0) { + key = strtok_r(str2, subdelim,&saveptr2); + if (key == NULL) + break; + i++; + } else if (i == 1) { + value = strtok_r(str2, subdelim,&saveptr2); + if (value == NULL) + break; + i = 0; + g_hash_table_insert(table, key, value); + } + } + } + +} + +static void ingress_priority_iterator(gpointer key, gpointer value ,gpointer user_data) +{ + struct rtnl_link *new_link = (struct rtnl_link *)user_data; + int from; + uint32_t to; + + errno = 0; + from = strtol((char *)key, NULL, 10); + if (errno == ERANGE) + return; + + errno = 0; + to = strtol((char *)value, NULL, 10); + if (errno == ERANGE) + return; + if ((from< 0) || (from> 7)) + return; + rtnl_link_vlan_set_ingress_map(new_link, from, to); +} + +static void egress_priority_iterator(gpointer key, gpointer value ,gpointer user_data) +{ + struct rtnl_link *new_link = (struct rtnl_link *)user_data; + uint32_t from; + int to; + + errno = 0; + from = strtol((char *)key, NULL, 10); + if (errno == ERANGE) + return; + + errno = 0; + to = strtol((char *)value, NULL, 10); + if (errno == ERANGE) + return; + if ((to< 0) || (to> 7)) + return; + rtnl_link_vlan_set_egress_map(new_link, from, 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 *orig_link = NULL, *new_link = NULL; + struct nl_sock *nlh = NULL; + struct nl_cache *cache = NULL; + + const char *interface_name = NULL; + const char *vlan_slave = NULL; + guint32 vlan_id = 0; + guint32 vlan_flags = 0; + + const char *delim = ","; + char *subdelim = ":"; + GHashTable *table; + + vlan_slave = nm_setting_vlan_get_vlan_slave(setting); + if (!vlan_slave) + return FALSE; + + vlan_id = nm_setting_vlan_get_vlan_id(setting); + if (vlan_id == 0) + return FALSE; + + nlh = nm_netlink_get_default_handle(); + if (!nlh) + return FALSE; + + ret = rtnl_link_alloc_cache(nlh,&cache); + if (ret< 0) + return FALSE; + + if (!cache) + return FALSE; + + orig_link = rtnl_link_get_by_name(cache, vlan_slave); + if (!orig_link) + goto free_cache; + + if_index = rtnl_link_get_ifindex(orig_link); + if (if_index<= 0) + goto free_orig_link;We've got: /* Generic utility functions */ int nm_netlink_iface_to_index (const char *iface); char * nm_netlink_index_to_iface (int idx); struct rtnl_link *nm_netlink_index_to_rtnl_link (int idx); struct nl_sock * nm_netlink_get_default_handle (void); in nm-netlink-monitor.c that we can use here to grab links and do name<->index lookups. The one thing that's missing would be nm_netlink_iface_to_rtnl_link() which we should add, and then you don't have to go through 10 lines to get links and lookups.
OK.
+ new_link = rtnl_link_alloc(); + if (!new_link) + goto free_orig_link; + + 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_vlan_set_id(new_link, vlan_id); + + interface_name = nm_setting_vlan_get_interface_name(setting); + if (interface_name) + rtnl_link_set_name(new_link, interface_name); + + vlan_flags = nm_setting_vlan_get_vlan_flags(setting); + if (vlan_flags) + rtnl_link_vlan_set_flags(new_link, vlan_flags); + + table = g_hash_table_new(g_str_hash, g_str_equal); + if (!table) + goto free_new_link; + + priority_parser(table, (char *)nm_setting_vlan_get_vlan_priority_ingress_map(setting), delim, subdelim); + g_hash_table_foreach(table, (GHFunc)ingress_priority_iterator, (gpointer)new_link); + g_hash_table_destroy(table);Yeah, best to parse these when reading them in. Note that when that's being done in ifcfg-rh/reader.c for the next revision, you can use g_strsplit_set (<string>, ",") and it'll give you a NULL terminated char** (which you can free with g_strfreev() when you're done with it), ie something like this: char **split, **iter; iter = split = g_strsplit_set (string, ","); if (!split) return; while (iter&& *iter) { <do something with *iter> } g_strfreev (split); Dan
many thanks Weiping Pan
+ table = g_hash_table_new(g_str_hash, g_str_equal); + if (!table) + goto free_new_link; + priority_parser(table, (char *)nm_setting_vlan_get_vlan_priority_egress_map(setting), delim, subdelim); + g_hash_table_foreach(table, (GHFunc)egress_priority_iterator, (gpointer)new_link); + g_hash_table_destroy(table); + + ret = rtnl_link_add(nlh, new_link, NLM_F_CREATE); + if (ret< 0) + goto free_new_link; + + rtnl_link_put(orig_link); + rtnl_link_put(new_link); + + return TRUE; + +free_new_link: + rtnl_link_put(new_link); + +free_orig_link: + rtnl_link_put(orig_link); + +free_cache: + nl_cache_free(cache); + 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); + if (!interface_name) + return FALSE; + + nlh = nm_netlink_get_default_handle(); + if (!nlh) + return FALSE; + + ret = rtnl_link_alloc_cache(nlh,&cache); + if (ret< 0) + return FALSE; + + if (!cache) + return 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 ae4e7d9..93f942c 100644 --- a/src/nm-system.h +++ b/src/nm-system.h @@ -30,6 +30,7 @@ #include<glib.h> #include "nm-device.h" #include "nm-ip4-config.h" +#include "nm-setting-vlan.h" /* Prototypes for system/distribution dependent functions, * implemented in the backend files in backends/ directory @@ -88,5 +89,7 @@ gboolean nm_system_iface_is_up (int ifindex); gboolean nm_system_iface_set_mtu (int ifindex, guint32 mtu); gboolean nm_system_iface_set_mac (int ifindex, const struct ether_addr *mac); +gboolean nm_system_add_vlan_device(NMSettingVLAN *setting); +gboolean nm_system_del_vlan_device(NMSettingVLAN *setting); #endif
_______________________________________________ networkmanager-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/networkmanager-list
