[lxc-devel] [RFC 2/2] lxc-user-nic: rename nic inside container to desired name

Serge Hallyn serge.hallyn at ubuntu.com
Tue Nov 5 20:56:42 UTC 2013


Quoting Stéphane Graber (stgraber at ubuntu.com):
> On Tue, Nov 05, 2013 at 02:15:00PM -0600, Serge Hallyn wrote:
> > To do so we do a quick setns into the container's netns.  This
> > (unexpectedly) turns out cleaner than trying to rename it from
> > lxc_setup(), because we don't know the original nic name in
> > the container until we created it which we do in the parent
> > after the init has been cloned.
> > 
> > Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
> 
> I think it may make sense to centralize that setns definition in

Actually lxc-user-nic can #include utils.h.

> something like namespace.h and the new netlinks function may make sense
> in network.c, but we can always do that later.

Yes, most of the network stuff can be consolidated.  I'll aim to clean
that up this week.

> Acked-by: Stéphane Graber <stgraber at ubuntu.com>
> 
> > ---
> >  src/lxc/conf.c         |   2 +-
> >  src/lxc/lxc_user_nic.c | 168 +++++++++++++++++++++++++++++++++++++++++++++----
> >  2 files changed, 158 insertions(+), 12 deletions(-)
> > 
> > diff --git a/src/lxc/conf.c b/src/lxc/conf.c
> > index afdaa14..5e1e18d 100644
> > --- a/src/lxc/conf.c
> > +++ b/src/lxc/conf.c
> > @@ -2761,7 +2761,7 @@ int unpriv_assign_nic(struct lxc_netdev *netdev, pid_t pid)
> >  
> >  	// Call lxc-user-nic pid type bridge
> >  	char pidstr[20];
> > -	char *args[] = { "lxc-user-nic", pidstr, "veth", netdev->link, NULL };
> > +	char *args[] = { "lxc-user-nic", pidstr, "veth", netdev->link, netdev->name, NULL };
> >  	snprintf(pidstr, 19, "%lu", (unsigned long) pid);
> >  	pidstr[19] = '\0';
> >  	execvp("lxc-user-nic", args);
> > diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c
> > index bc1c268..dc35e55 100644
> > --- a/src/lxc/lxc_user_nic.c
> > +++ b/src/lxc/lxc_user_nic.c
> > @@ -17,6 +17,7 @@
> >   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> >   */
> >  
> > +#define _GNU_SOURCE             /* See feature_test_macros(7) */
> >  #include <stdio.h>
> >  #include <stdlib.h>
> >  #include <stdbool.h>
> > @@ -27,6 +28,7 @@
> >  #include <sys/file.h>
> >  #include <alloca.h>
> >  #include <string.h>
> > +#include <sched.h>
> >  #include <sys/mman.h>
> >  #include <sys/socket.h>
> >  #include <errno.h>
> > @@ -39,9 +41,13 @@
> >  #include <net/if_arp.h>
> >  #include <netinet/in.h>
> >  #include <linux/if_bridge.h>
> > +#include <linux/netlink.h>
> >  #include <linux/rtnetlink.h>
> >  #include <linux/sockios.h>
> > +#include <sys/param.h>
> > +#include <sched.h>
> >  #include "config.h"
> > +#include "utils.h"
> >  
> >  #ifndef HAVE_GETLINE
> >  #ifdef HAVE_FGETLN
> > @@ -49,6 +55,19 @@
> >  #endif
> >  #endif
> >  
> > +/* Define setns() if missing from the C library */
> > +#ifndef HAVE_SETNS
> > +static inline int setns(int fd, int nstype)
> > +{
> > +#ifdef __NR_setns
> > +	return syscall(__NR_setns, fd, nstype);
> > +#else
> > +	errno = ENOSYS;
> > +	return -1;
> > +#endif
> > +}
> > +#endif
> > +
> >  #if ISTEST
> >  #define CONF_FILE "/tmp/lxc-usernet"
> >  #define DB_FILE "/tmp/nics"
> > @@ -94,7 +113,8 @@
> >  
> >  void usage(char *me, bool fail)
> >  {
> > -	fprintf(stderr, "Usage: %s pid type bridge\n", me);
> > +	fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
> > +	fprintf(stderr, " nicname is the name to use inside the container\n");
> >  	exit(fail ? 1 : 0);
> >  }
> >  
> > @@ -237,12 +257,13 @@ bool nic_exists(char *nic)
> >  	return true;
> >  }
> >  
> > -#if ! ISTEST
> >  struct link_req {
> >  	struct nlmsg nlmsg;
> >  	struct ifinfomsg ifinfomsg;
> >  };
> >  
> > +#if ! ISTEST
> > +
> >  int lxc_veth_create(const char *name1, const char *name2)
> >  {
> >  	struct nl_handler nlh;
> > @@ -539,7 +560,7 @@ int lxc_netdev_delete_by_name(const char *name)
> >  
> >  #endif
> >  
> > -bool create_nic(char *nic, char *br, char *pidstr)
> > +bool create_nic(char *nic, char *br, char *pidstr, char **cnic)
> >  {
> >  #if ISTEST
> >  	char path[200];
> > @@ -559,7 +580,7 @@ bool create_nic(char *nic, char *br, char *pidstr)
> >  
> >  	ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
> >  	if (ret < 0 || ret >= IFNAMSIZ) {
> > -		fprintf(stderr, "nic name too long\n");
> > +		fprintf(stderr, "host nic name too long\n");
> >  		exit(1);
> >  	}
> >  
> > @@ -581,6 +602,7 @@ bool create_nic(char *nic, char *br, char *pidstr)
> >  		fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
> >  		goto out_del;
> >  	}
> > +	*cnic = strdup(veth2buf);
> >  	return true;
> >  
> >  out_del:
> > @@ -589,14 +611,19 @@ out_del:
> >  #endif
> >  }
> >  
> > -void get_new_nicname(char **dest, char *br, char *pid)
> > +/*
> > + * Get a new nic.
> > + * *dest will container the name (lxcuser-%d) which is attached
> > + * on the host to the lxc bridge
> > + */
> > +void get_new_nicname(char **dest, char *br, char *pid, char **cnic)
> >  {
> >  	int i = 0;
> >  	// TODO - speed this up.  For large installations we won't
> >  	// want n stats for every nth container startup.
> >  	while (1) {
> >  		sprintf(*dest, "lxcuser-%d", i);
> > -		if (!nic_exists(*dest) && create_nic(*dest, br, pid))
> > +		if (!nic_exists(*dest) && create_nic(*dest, br, pid, cnic))
> >  			return;
> >  		i++;
> >  	}
> > @@ -672,7 +699,7 @@ int count_entries(char *buf, off_t len, char *me, char *t, char *br)
> >   * The dbfile has lines of the format:
> >   * user type bridge nicname
> >   */
> > -bool get_nic_if_avail(int fd, char *me, char *pid, char *intype, char *br, int allowed, char **nicname)
> > +bool get_nic_if_avail(int fd, char *me, char *pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
> >  {
> >  	off_t len, slen;
> >  	struct stat sb;
> > @@ -696,7 +723,7 @@ bool get_nic_if_avail(int fd, char *me, char *pid, char *intype, char *br, int a
> >  	}
> >  
> >  
> > -	get_new_nicname(nicname, br, pid);
> > +	get_new_nicname(nicname, br, pid, cnic);
> >  	/* me  ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
> >  	slen = strlen(me) + strlen(intype) + strlen(br) + strlen(*nicname) + 5;
> >  	newline = alloca(slen);
> > @@ -743,20 +770,134 @@ again:
> >  	goto again;
> >  }
> >  
> > +static int lxc_netdev_rename_by_index(int ifindex, const char *newname)
> > +{
> > +	struct nl_handler nlh;
> > +	struct nlmsg *nlmsg = NULL, *answer = NULL;
> > +	struct link_req *link_req;
> > +	int len, err;
> > +
> > +	err = netlink_open(&nlh, NETLINK_ROUTE);
> > +	if (err)
> > +		return err;
> > +
> > +	len = strlen(newname);
> > +	if (len == 1 || len >= IFNAMSIZ)
> > +		goto out;
> > +
> > +	err = -ENOMEM;
> > +	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
> > +	if (!nlmsg)
> > +		goto out;
> > +
> > +	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
> > +	if (!answer)
> > +		goto out;
> > +
> > +	link_req = (struct link_req *)nlmsg;
> > +	link_req->ifinfomsg.ifi_family = AF_UNSPEC;
> > +	link_req->ifinfomsg.ifi_index = ifindex;
> > +	nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
> > +	nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST;
> > +	nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;
> > +
> > +	if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
> > +		goto out;
> > +
> > +	err = netlink_transaction(&nlh, nlmsg, answer);
> > +out:
> > +	netlink_close(&nlh);
> > +	nlmsg_free(answer);
> > +	nlmsg_free(nlmsg);
> > +	return err;
> > +}
> > +
> > +static int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
> > +{
> > +	int len, index;
> > +
> > +	len = strlen(oldname);
> > +	if (len == 1 || len >= IFNAMSIZ)
> > +		return -EINVAL;
> > +
> > +	index = if_nametoindex(oldname);
> > +	if (!index) {
> > +		fprintf(stderr, "Error getting ifindex for %s\n", oldname);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return lxc_netdev_rename_by_index(index, newname);
> > +}
> > +
> > +int rename_in_ns(int pid, char *oldname, char *newname)
> > +{
> > +	char nspath[MAXPATHLEN];
> > +	int fd = -1, ofd = -1, ret;
> > +
> > +	ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", getpid());
> > +	if (ret < 0 || ret >= MAXPATHLEN)
> > +		return -1;
> > +	if ((ofd = open(nspath, O_RDONLY)) < 0) {
> > +		fprintf(stderr, "Opening %s\n", nspath);
> > +		return -1;
> > +	}
> > +	ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", pid);
> > +	if (ret < 0 || ret >= MAXPATHLEN)
> > +		goto out_err;
> > +
> > +	if ((fd = open(nspath, O_RDONLY)) < 0) {
> > +		fprintf(stderr, "Opening %s\n", nspath);
> > +		goto out_err;
> > +	}
> > +	if (setns(fd, 0) < 0) {
> > +		fprintf(stderr, "setns to container network namespace\n");
> > +		goto out_err;
> > +	}
> > +	close(fd); fd = -1;
> > +	if ((ret = lxc_netdev_rename_by_name(oldname, newname)) < 0) {
> > +		fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, newname);
> > +		goto out_err;
> > +	}
> > +	if (setns(ofd, 0) < 0) {
> > +		fprintf(stderr, "Error returning to original netns\n");
> > +		close(ofd);
> > +		return -1;
> > +	}
> > +	close(ofd);
> > +
> > +	return 0;
> > +
> > +out_err:
> > +	if (ofd >= 0)
> > +		close(ofd);
> > +	if (setns(ofd, 0) < 0)
> > +		fprintf(stderr, "Error returning to original network namespace\n");
> > +	if (fd >= 0)
> > +		close(fd);
> > +	return -1;
> > +}
> > +
> >  int main(int argc, char *argv[])
> >  {
> >  	int n, fd;
> >  	bool gotone = false;
> >  	char *me, *buf = alloca(400);
> >  	char *nicname = alloca(40);
> > +	char *cnic; // created nic name in container is returned here.
> > +	char *vethname;
> > +	int pid;
> >  
> >  	if ((me = get_username(&buf)) == NULL) {
> >  		fprintf(stderr, "Failed to get username\n");
> >  		exit(1);
> >  	}
> >  
> > -	if (argc != 4)
> > +	if (argc < 4)
> >  		usage(argv[0], true);
> > +	if (argc >= 5)
> > +		vethname = argv[4];
> > +	else
> > +		vethname = "eth0";
> >  
> >  	if (!create_db_dir(DB_FILE)) {
> >  		fprintf(stderr, "Failed to create directory for db file\n");
> > @@ -770,14 +911,19 @@ int main(int argc, char *argv[])
> >  
> >  	n = get_alloted(me, argv[2], argv[3]);
> >  	if (n > 0)
> > -		gotone = get_nic_if_avail(fd, me, argv[1], argv[2], argv[3], n, &nicname);
> > +		gotone = get_nic_if_avail(fd, me, argv[1], argv[2], argv[3], n, &nicname, &cnic);
> >  	close(fd);
> >  	if (!gotone) {
> >  		fprintf(stderr, "Quota reached\n");
> >  		exit(1);
> >  	}
> >  
> > -	// Now create the link
> > +	pid = atoi(argv[1]);
> > +	// Now rename the link
> > +	if (rename_in_ns(pid, cnic, vethname) < 0) {
> > +		fprintf(stderr, "Failed to rename the link\n");
> > +		exit(1);
> > +	}
> >  
> >  	exit(0);
> >  }
> > -- 
> > 1.8.4.2
> > 
> > 
> > ------------------------------------------------------------------------------
> > November Webinars for C, C++, Fortran Developers
> > Accelerate application performance with scalable programming models. Explore
> > techniques for threading, error checking, porting, and tuning. Get the most 
> > from the latest Intel processors and coprocessors. See abstracts and register
> > http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
> > _______________________________________________
> > Lxc-devel mailing list
> > Lxc-devel at lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/lxc-devel
> 
> -- 
> Stéphane Graber
> Ubuntu developer
> http://www.ubuntu.com






More information about the lxc-devel mailing list