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 <[email protected]>
> ---
>  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;
>  }


_______________________________________________
networkmanager-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to