Re: [PATCH V2] vlan: add compatible functions for libnl1



On Thu, 2012-02-23 at 11:11 +0800, Weiping Pan wrote:
> If we want to support vlan without libnl3,
> then we can use ioctl.

Pushed, thanks!

Dan

> Changelog:
> V2: fix identation and comments.
> 
> Signed-off-by: Weiping Pan <wpan redhat com>
> ---
>  src/nm-netlink-compat.c |  137 ++++++++++++++++++++++++++++
>  src/nm-netlink-compat.h |   31 +------
>  src/nm-system.c         |  229 ++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 368 insertions(+), 29 deletions(-)
> 
> diff --git a/src/nm-netlink-compat.c b/src/nm-netlink-compat.c
> index e91a1ff..974121a 100644
> --- a/src/nm-netlink-compat.c
> +++ b/src/nm-netlink-compat.c
> @@ -20,7 +20,13 @@
>  
>  #include <config.h>
>  #include <glib.h>
> +#include <unistd.h>
> +#include <sys/ioctl.h>
> +#include <sys/socket.h>
> +#include <linux/if_vlan.h>
> +#include <linux/sockios.h>
>  
> +#include "nm-logging.h"
>  #include "nm-netlink-compat.h"
>  
>  #ifndef HAVE_LIBNL1
> @@ -102,4 +108,135 @@ nl_compat_error (int err)
>  
>  	return -err;
>  }
> +
> +int
> +rtnl_link_vlan_get_id (struct rtnl_link *l)
> +{
> +	int fd;
> +	struct vlan_ioctl_args if_request;
> +	char *if_name = NULL;
> +
> +	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
> +
> +	if ((if_name = rtnl_link_get_name (l)) == NULL)
> +		return -1;
> +
> +	strcpy (if_request.device1, if_name);
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	if_request.cmd = GET_VLAN_VID_CMD;
> +	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't get vlan id for %s.", if_name);
> +		goto err_out;
> +	}
> +
> +	close(fd);
> +	return if_request.u.VID;
> +err_out:
> +	close(fd);
> +	return -1;
> +}
> +
> +int
> +rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags)
> +{
> +	int fd;
> +	struct vlan_ioctl_args if_request;
> +	char *if_name = NULL;
> +
> +
> +	if ((if_name = rtnl_link_get_name (l)) == NULL)
> +		return -1;
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
> +	strcpy (if_request.device1, if_name);
> +	if_request.cmd = SET_VLAN_FLAG_CMD;
> +	if_request.u.flag = flags;
> +
> +	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't set flag in device %s.", if_name);
> +		goto err_out;
> +	}
> +
> +	close(fd);
> +	return 0;
> +err_out:
> +	close(fd);
> +	return -1;
> +}
> +
> +int
> +rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to)
> +{
> +	int fd;
> +	struct vlan_ioctl_args if_request;
> +	char *if_name = NULL;
> +
> +	if ((if_name = rtnl_link_get_name (l)) == NULL)
> +		return -1;
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
> +	strcpy (if_request.device1, if_name);
> +	if_request.cmd = SET_VLAN_INGRESS_PRIORITY_CMD;
> +	if_request.u.skb_priority = from;
> +	if_request.vlan_qos = to;
> +
> +	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't set ingress map on device %s.", if_name);
> +		goto err_out;
> +	}
> +
> +	close(fd);
> +	return 0;
> +err_out:
> +	close(fd);
> +	return -1;
> +}
> +
> +int
> +rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to)
> +{
> +	int fd;
> +	struct vlan_ioctl_args if_request;
> +	char *if_name = NULL;
> +
> +	if ((if_name = rtnl_link_get_name (l)) == NULL)
> +		return -1;
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
> +	strcpy (if_request.device1, if_name);
> +	if_request.cmd = SET_VLAN_EGRESS_PRIORITY_CMD;
> +	if_request.u.skb_priority = from;
> +	if_request.vlan_qos = to;
> +
> +	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't set egress map on device %s.", if_name);
> +		goto err_out;
> +	}
> +
> +	close(fd);
> +	return 0;
> +err_out:
> +	close(fd);
> +	return -1;
> +}
>  #endif
> diff --git a/src/nm-netlink-compat.h b/src/nm-netlink-compat.h
> index 6178eb6..eb0926a 100644
> --- a/src/nm-netlink-compat.h
> +++ b/src/nm-netlink-compat.h
> @@ -251,33 +251,10 @@ rtnl_link_vlan_set_id (struct rtnl_link *l, int id)
>  	return -NLE_OPNOTSUPP;
>  }
>  
> -static inline int
> -rtnl_link_vlan_get_id (struct rtnl_link *l)
> -{
> -	/* VLAN only in libnl3 */
> -	return -NLE_OPNOTSUPP;
> -}
> -
> -static inline int
> -rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags)
> -{
> -	/* VLAN only in libnl3 */
> -	return -NLE_OPNOTSUPP;
> -}
> -
> -static inline int
> -rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to)
> -{
> -	/* VLAN only in libnl3 */
> -	return -NLE_OPNOTSUPP;
> -}
> -
> -static inline int
> -rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to)
> -{
> -	/* VLAN only in libnl3 */
> -	return -NLE_OPNOTSUPP;
> -}
> +int rtnl_link_vlan_get_id (struct rtnl_link *l);
> +int rtnl_link_vlan_set_flags (struct rtnl_link *l, unsigned int flags);
> +int rtnl_link_vlan_set_ingress_map (struct rtnl_link *l, int from, uint32_t to);
> +int rtnl_link_vlan_set_egress_map (struct rtnl_link *l, int from, uint32_t to);
>  
>  static inline int
>  rtnl_link_set_type (struct rtnl_link *l, const char *type)
> diff --git a/src/nm-system.c b/src/nm-system.c
> index 8202d82..8c57def 100644
> --- a/src/nm-system.c
> +++ b/src/nm-system.c
> @@ -1574,6 +1574,216 @@ nm_system_get_iface_vlan_info (int ifindex,
>  	return success;
>  }
>  
> +static gboolean
> +nm_system_iface_compat_set_name (const char *old_name, const char *new_name)
> +{
> +	int fd;
> +	struct ifreq ifr;
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	memset (&ifr, 0, sizeof (struct ifreq));
> +	strncpy (ifr.ifr_name, old_name, sizeof (ifr.ifr_name));
> +	strncpy (ifr.ifr_newname, new_name, sizeof (ifr.ifr_newname));
> +
> +	if (ioctl (fd, SIOCSIFNAME, &ifr) < 0) {
> +		nm_log_err (LOGD_DEVICE, "cann't change %s with %s.", old_name, new_name);
> +		close (fd);
> +		return FALSE;
> +	}
> +
> +	close (fd);
> +	return TRUE;
> +}
> +
> +static gboolean
> +nm_system_iface_compat_set_vlan_name_type (int name_type)
> +{
> +	int fd;
> +	struct vlan_ioctl_args if_request;
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
> +	if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
> +	if_request.u.name_type = name_type;
> +
> +	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't set name type.");
> +		close (fd);
> +		return FALSE;
> +	}
> +
> +	close (fd);
> +	return TRUE;
> +}
> +
> +static gboolean
> +nm_system_iface_compat_add_vlan_device (const char *master, int vid)
> +{
> +	int fd;
> +	struct vlan_ioctl_args if_request;
> +
> +	g_return_val_if_fail (master, FALSE);
> +	g_return_val_if_fail (vid < 4096, FALSE);
> +
> +	/*
> +	 * use VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD as default,
> +	 * we will overwrite it with rtnl_link_set_name() later.
> +	 */
> +	if (!nm_system_iface_compat_set_vlan_name_type (VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD))
> +		return FALSE;
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
> +	strcpy (if_request.device1, master);
> +	if_request.cmd = ADD_VLAN_CMD;
> +	if_request.u.VID = vid;
> +
> +	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't add vlan device %s vid %d.", master, vid);
> +		close (fd);
> +		return FALSE;
> +	}
> +
> +	close (fd);
> +	return TRUE;
> +}
> +
> +static gboolean
> +nm_system_iface_compat_rem_vlan_device (const char *iface)
> +{
> +	int fd;
> +	struct vlan_ioctl_args if_request;
> +
> +	if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
> +		return -1;
> +	}
> +
> +	memset (&if_request, 0, sizeof (struct vlan_ioctl_args));
> +        strcpy (if_request.device1, iface);
> +	if_request.cmd = DEL_VLAN_CMD;
> +
> +	if (ioctl (fd, SIOCSIFVLAN, &if_request) < 0) {
> +		nm_log_err (LOGD_DEVICE, "couldn't rem vlan device %s.", iface);
> +		close (fd);
> +		return FALSE;
> +	}
> +
> +	close (fd);
> +	return TRUE;
> +}
> +
> +static gboolean
> +nm_system_iface_compat_add_vlan (NMConnection *connection,
> +				const char *iface,
> +				int master_ifindex)
> +{
> +	NMSettingVlan *s_vlan;
> +	int vlan_id;
> +	guint32 vlan_flags = 0;
> +	guint32 num, i, from, to;
> +	int ifindex;
> +	struct rtnl_link *new_link = NULL;
> +	char *master = nm_netlink_index_to_iface (master_ifindex);
> +	char *name = NULL;
> +
> +	s_vlan = nm_connection_get_setting_vlan (connection);
> +	g_return_val_if_fail (s_vlan, FALSE);
> +
> +	vlan_id = nm_setting_vlan_get_id (s_vlan);
> +
> +	if (!iface) {
> +		iface = nm_connection_get_virtual_iface_name (connection);
> +		g_return_val_if_fail (iface != NULL, FALSE);
> +	}
> +
> +	/*
> +	 * Use VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD as default,
> +	 * we will overwrite it with rtnl_link_set_name() later.
> +	 */
> +	name = nm_utils_new_vlan_name(master, vlan_id);
> +
> +	/*
> +	 * vconfig add
> +	 */
> +
> +	if (!nm_system_iface_compat_add_vlan_device (master, vlan_id))
> +		goto err_out;
> +
> +	/*
> +	 * get corresponding rtnl_link
> +	 */
> +
> +	if (!nm_system_iface_compat_set_name (name, iface))
> +		goto err_out_delete_vlan_with_default_name;
> +
> +	ifindex = nm_netlink_iface_to_index (iface);
> +	if (ifindex <= 0)
> +		goto err_out;
> +
> +	new_link = nm_netlink_index_to_rtnl_link (ifindex);
> +	if (!new_link)
> +		goto err_out_delete_vlan_with_default_name;
> +
> +	/*
> +	 * vconfig set_flag
> +	 */
> +	vlan_flags = nm_setting_vlan_get_flags (s_vlan);
> +	if (vlan_flags)
> +		if (rtnl_link_vlan_set_flags (new_link, vlan_flags))
> +			goto err_out_delete_vlan_with_new_name;
> +
> +	/*
> +	 * vconfig set_ingress_map
> +	 */
> +	num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP);
> +	for (i = 0; i < num; i++) {
> +		if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to))
> +			if (rtnl_link_vlan_set_ingress_map (new_link, from, to))
> +				goto err_out_delete_vlan_with_new_name;
> +	}
> +
> +	/*
> +	 * vconfig set_egress_map
> +	 */
> +	num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP);
> +	for (i = 0; i < num; i++) {
> +		if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to))
> +			if (rtnl_link_vlan_set_egress_map (new_link, from, to))
> +				goto err_out_delete_vlan_with_new_name;
> +	}
> +
> +	rtnl_link_put (new_link);
> +	return TRUE;
> +
> +err_out:
> +	g_free (name);
> +	return FALSE;
> +
> +err_out_delete_vlan_with_default_name:
> +	nm_system_iface_compat_rem_vlan_device (name);
> +	g_free (name);
> +	return FALSE;
> +
> +err_out_delete_vlan_with_new_name:
> +	rtnl_link_put (new_link);
> +	nm_system_iface_compat_rem_vlan_device (iface);
> +	g_free (name);
> +	return FALSE;
> +}
> +
>  /**
>   * nm_system_add_vlan_iface:
>   * @connection: the #NMConnection that describes the VLAN interface
> @@ -1620,8 +1830,15 @@ nm_system_add_vlan_iface (NMConnection *connection,
>  	}
>  
>  	ret = rtnl_link_set_type (new_link, "vlan");
> -	if (ret < 0)
> +	if (ret == -NLE_OPNOTSUPP) {
> +		/*
> +		 * There is no linbl3, try ioctl.
> +		 */
> +		ret = -1;
> +		if (nm_system_iface_compat_add_vlan (connection, iface, master_ifindex))
> +			ret = 0;
>  		goto out;
> +	}
>  
>  	rtnl_link_set_link (new_link, master_ifindex);
>  	rtnl_link_set_name (new_link, iface);
> @@ -1693,9 +1910,17 @@ nm_system_del_vlan_iface (const char *iface)
>  	new_link = rtnl_link_get_by_name (cache, iface);
>  	if (new_link) {
>  		ret = rtnl_link_delete (nlh, new_link);
> -		rtnl_link_put (new_link);
> +		if (ret == -NLE_OPNOTSUPP) {
> +			/*
> +			 * There is no linbl3, try ioctl.
> +			 */
> +			ret = -1;
> +			if (nm_system_iface_compat_rem_vlan_device (iface))
> +				ret = 0;
> +		}
>  	}
>  
> +	rtnl_link_put (new_link);
>  	nl_cache_free (cache);
>  	return (ret == 0) ? TRUE : FALSE;
>  }




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