Re: [PATCH V2] vlan: add compatible functions for libnl1
- From: Dan Williams <dcbw redhat com>
- To: Weiping Pan <wpan redhat com>
- Cc: tgraf redhat com, networkmanager-list gnome org
- Subject: Re: [PATCH V2] vlan: add compatible functions for libnl1
- Date: Fri, 24 Feb 2012 14:33:56 -0600
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]