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
