Re: [PATCH 3/6] VLAN: create/delete kernel vlan device



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<wpan redhat com>
---
  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




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