[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