LCOV - code coverage report
Current view: top level - home/snorch/criu - tun.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 8 183 4.4 %
Date: 2014-04-22 Functions: 1 12 8.3 %
Branches: 3 104 2.9 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <sys/socket.h>
       3                 :            : #include <linux/if.h>
       4                 :            : #include <linux/if_tun.h>
       5                 :            : #include <sys/ioctl.h>
       6                 :            : 
       7                 :            : #include "cr_options.h"
       8                 :            : #include "fdset.h"
       9                 :            : #include "protobuf.h"
      10                 :            : #include "cr-show.h"
      11                 :            : #include "string.h"
      12                 :            : #include "files.h"
      13                 :            : #include "files-reg.h"
      14                 :            : #include "tun.h"
      15                 :            : #include "net.h"
      16                 :            : #include "namespaces.h"
      17                 :            : 
      18                 :            : #include "protobuf/tun.pb-c.h"
      19                 :            : 
      20                 :            : #ifndef IFF_PERSIST
      21                 :            : #define IFF_PERSIST 0x0800
      22                 :            : #endif
      23                 :            : 
      24                 :            : #ifndef IFF_NOFILTER
      25                 :            : #define IFF_NOFILTER 0x1000
      26                 :            : #endif
      27                 :            : 
      28                 :            : #ifndef TUNSETQUEUE
      29                 :            : #define TUNSETQUEUE  _IOW('T', 217, int)
      30                 :            : #define IFF_ATTACH_QUEUE 0x0200
      31                 :            : #define IFF_DETACH_QUEUE 0x0400
      32                 :            : #endif
      33                 :            : 
      34                 :            : /*
      35                 :            :  * Absense of the 1st ioctl means we cannot restore tun link. But
      36                 :            :  * since the 2nd one appeared at the same time, we'll "check" this
      37                 :            :  * by trying to dump filter and abort dump if it's not there.
      38                 :            :  */
      39                 :            : 
      40                 :            : #ifndef TUNSETIFINDEX
      41                 :            : #define TUNSETIFINDEX _IOW('T', 218, unsigned int)
      42                 :            : #endif
      43                 :            : 
      44                 :            : #ifndef TUNGETFILTER
      45                 :            : #define TUNGETFILTER _IOR('T', 219, struct sock_fprog)
      46                 :            : #endif
      47                 :            : 
      48                 :            : #define TUN_DEV_GEN_PATH        "/dev/net/tun"
      49                 :            : 
      50                 :          2 : int check_tun(void)
      51                 :            : {
      52                 :          2 :         int fd, idx = 13, ret;
      53                 :            : 
      54         [ -  + ]:          2 :         if (opts.check_ms_kernel) {
      55                 :          0 :                 pr_warn("Skipping tun support check\n");
      56                 :          0 :                 return 0;
      57                 :            :         }
      58                 :            : 
      59                 :            :         fd = open(TUN_DEV_GEN_PATH, O_RDWR);
      60         [ -  + ]:          2 :         if (fd < 0) {
      61                 :          0 :                 pr_perror("Can't check tun support");
      62                 :          0 :                 return 0;
      63                 :            :         }
      64                 :            : 
      65                 :          2 :         ret = ioctl(fd, TUNSETIFINDEX, &idx);
      66         [ -  + ]:          2 :         if (ret < 0)
      67                 :          0 :                 pr_perror("No proper support for tun dump/restore");
      68                 :            : 
      69                 :          2 :         close(fd);
      70                 :          2 :         return ret;
      71                 :            : }
      72                 :            : 
      73                 :            : static LIST_HEAD(tun_links);
      74                 :            : 
      75                 :            : struct tun_link {
      76                 :            :         char name[IFNAMSIZ];
      77                 :            :         struct list_head l;
      78                 :            :         union {
      79                 :            :                 struct {
      80                 :            :                         unsigned flags;
      81                 :            :                 } rst;
      82                 :            : 
      83                 :            :                 struct {
      84                 :            :                         unsigned sndbuf;
      85                 :            :                         unsigned vnethdr;
      86                 :            :                 } dmp;
      87                 :            :         };
      88                 :            : };
      89                 :            : 
      90                 :          0 : static int list_tun_link(NetDeviceEntry *nde)
      91                 :            : {
      92                 :            :         struct tun_link *tl;
      93                 :            : 
      94         [ #  # ]:          0 :         tl = xmalloc(sizeof(*tl));
      95         [ #  # ]:          0 :         if (!tl)
      96                 :            :                 return -1;
      97                 :            : 
      98                 :          0 :         strlcpy(tl->name, nde->name, sizeof(tl->name));
      99                 :            :         /*
     100                 :            :          * Keep tun-flags not only for persistency fixup (see
     101                 :            :          * commend below), but also for TUNSETIFF -- we must
     102                 :            :          * open the device with the same flags it should live
     103                 :            :          * with (i.e. -- with which it was created.
     104                 :            :          */
     105                 :          0 :         tl->rst.flags = nde->tun->flags;
     106                 :          0 :         list_add_tail(&tl->l, &tun_links);
     107                 :            :         return 0;
     108                 :            : }
     109                 :            : 
     110                 :          0 : static struct tun_link *find_tun_link(char *name)
     111                 :            : {
     112                 :            :         struct tun_link *tl;
     113                 :            : 
     114         [ #  # ]:          0 :         list_for_each_entry(tl, &tun_links, l)
     115         [ #  # ]:          0 :                 if (!strcmp(tl->name, name))
     116                 :            :                         return tl;
     117                 :            : 
     118                 :            :         return NULL;
     119                 :            : }
     120                 :            : 
     121                 :          0 : static struct tun_link *__dump_tun_link_fd(int fd, char *name, unsigned flags)
     122                 :            : {
     123                 :            :         struct tun_link *tl;
     124                 :            :         struct sock_fprog flt;
     125                 :            : 
     126         [ #  # ]:          0 :         tl = xmalloc(sizeof(*tl));
     127         [ #  # ]:          0 :         if (!tl)
     128                 :            :                 goto err;
     129                 :          0 :         strlcpy(tl->name, name, sizeof(tl->name));
     130                 :            : 
     131         [ #  # ]:          0 :         if (ioctl(fd, TUNGETVNETHDRSZ, &tl->dmp.vnethdr) < 0) {
     132                 :          0 :                 pr_perror("Can't dump vnethdr size for %s", name);
     133                 :          0 :                 goto err;
     134                 :            :         }
     135                 :            : 
     136         [ #  # ]:          0 :         if (ioctl(fd, TUNGETSNDBUF, &tl->dmp.sndbuf) < 0) {
     137                 :          0 :                 pr_perror("Can't dump sndbuf for %s", name);
     138                 :          0 :                 goto err;
     139                 :            :         }
     140                 :            : 
     141         [ #  # ]:          0 :         if (flags & IFF_TAP) {
     142                 :          0 :                 pr_debug("Checking filter for tap %s\n", name);
     143         [ #  # ]:          0 :                 if (ioctl(fd, TUNGETFILTER, &flt) < 0) {
     144                 :          0 :                         pr_perror("Can't get tun filter for %s", name);
     145                 :          0 :                         goto err;
     146                 :            :                 }
     147                 :            : 
     148                 :            :                 /*
     149                 :            :                  * TUN filters are tricky -- the program itself is 'somewhere'
     150                 :            :                  * in the task's memory, so we can't get one for unattached
     151                 :            :                  * persistent device. The only way for doing it is opening the
     152                 :            :                  * device with IFF_NOFILTER and attaching some fake one :(
     153                 :            :                  */
     154                 :            : 
     155         [ #  # ]:          0 :                 if (flt.len != 0) {
     156                 :          0 :                         pr_err("Can't dump %s with filter on-board\n", name);
     157                 :          0 :                         goto err;
     158                 :            :                 }
     159         [ #  # ]:          0 :         } else if (!(flags & IFF_NOFILTER)) {
     160                 :          0 :                 pr_err("No info about %s filter, kernel is too old\n", name);
     161                 :          0 :                 goto err;
     162                 :            :         }
     163                 :            : 
     164                 :          0 :         return tl;
     165                 :            : 
     166                 :            : err:
     167         [ #  # ]:          0 :         xfree(tl);
     168                 :            :         return NULL;
     169                 :            : }
     170                 :            : 
     171                 :          0 : static struct tun_link *dump_tun_link_fd(int fd, char *name, unsigned flags)
     172                 :            : {
     173                 :            :         struct tun_link *tl;
     174                 :            : 
     175                 :          0 :         tl = find_tun_link(name);
     176         [ #  # ]:          0 :         if (tl)
     177                 :            :                 return tl;
     178                 :            : 
     179                 :          0 :         tl = __dump_tun_link_fd(fd, name, flags);
     180         [ #  # ]:          0 :         if (tl)
     181                 :            :                 /*
     182                 :            :                  * Keep this in list till links dumping code starts.
     183                 :            :                  * We can't let it dump all this stuff itself, since
     184                 :            :                  * multiple attaches to one tun device is limited and
     185                 :            :                  * we may not be able to it that late.
     186                 :            :                  *
     187                 :            :                  * For persistent detached devices the get_tun_link_fd
     188                 :            :                  * will attach to the device and get the needed stuff.
     189                 :            :                  */
     190                 :          0 :                 list_add(&tl->l, &tun_links);
     191                 :            : 
     192                 :          0 :         return tl;
     193                 :            : }
     194                 :            : 
     195                 :          0 : static int open_tun_dev(char *name, unsigned int idx, unsigned flags)
     196                 :            : {
     197                 :            :         int fd;
     198                 :            :         struct ifreq ifr;
     199                 :            : 
     200                 :            :         fd = open(TUN_DEV_GEN_PATH, O_RDWR);
     201         [ #  # ]:          0 :         if (fd < 0) {
     202                 :          0 :                 pr_perror("Can't open tun device");
     203                 :          0 :                 return -1;
     204                 :            :         }
     205                 :            : 
     206         [ #  # ]:          0 :         if (idx) {
     207                 :          0 :                 pr_debug("  restoring %u for %s tun\n", idx, name);
     208         [ #  # ]:          0 :                 if (ioctl(fd, TUNSETIFINDEX, &idx) < 0) {
     209                 :          0 :                         pr_perror("Can't restore tun's index");
     210                 :          0 :                         goto err;
     211                 :            :                 }
     212                 :            :         }
     213                 :            : 
     214                 :            :         memset(&ifr, 0, sizeof(ifr));
     215                 :          0 :         strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
     216                 :          0 :         ifr.ifr_flags = flags;
     217                 :            : 
     218         [ #  # ]:          0 :         if (ioctl(fd, TUNSETIFF, &ifr)) {
     219                 :          0 :                 pr_perror("Can't create tun device");
     220                 :          0 :                 goto err;
     221                 :            :         }
     222                 :            : 
     223                 :            :         return fd;
     224                 :            : 
     225                 :            : err:
     226                 :          0 :         close(fd);
     227                 :          0 :         return -1;
     228                 :            : }
     229                 :            : 
     230                 :          0 : static struct tun_link *get_tun_link_fd(char *name, unsigned flags)
     231                 :            : {
     232                 :            :         struct tun_link *tl;
     233                 :            :         int fd;
     234                 :            : 
     235                 :          0 :         tl = find_tun_link(name);
     236         [ #  # ]:          0 :         if (tl)
     237                 :            :                 return tl;
     238                 :            : 
     239                 :            :         /*
     240                 :            :          * If we haven't found this thing, then the
     241                 :            :          * device we see via netlink exists w/o any fds
     242                 :            :          * attached, i.e. -- it's persistent
     243                 :            :          */
     244                 :            : 
     245         [ #  # ]:          0 :         if (!(flags & IFF_PERSIST)) {
     246                 :          0 :                 pr_err("No fd infor for non persistent tun device %s\n", name);
     247                 :          0 :                 return NULL;
     248                 :            :         }
     249                 :            : 
     250                 :            :         /*
     251                 :            :          * Kernel will try to attach filter (if it exists) to our memory,
     252                 :            :          * avoid this.
     253                 :            :          */
     254                 :            : 
     255                 :          0 :         flags |= IFF_NOFILTER;
     256                 :            : 
     257                 :          0 :         fd = open_tun_dev(name, 0, flags);
     258         [ #  # ]:          0 :         if (fd < 0)
     259                 :            :                 return NULL;
     260                 :            : 
     261                 :          0 :         tl = __dump_tun_link_fd(fd, name, flags);
     262                 :          0 :         close(fd);
     263                 :            : 
     264                 :          0 :         return tl;
     265                 :            : }
     266                 :            : 
     267                 :          0 : static int dump_tunfile(int lfd, u32 id, const struct fd_parms *p)
     268                 :            : {
     269                 :          0 :         int ret, img = fdset_fd(glob_fdset, CR_FD_TUNFILE);
     270                 :          0 :         TunfileEntry tfe = TUNFILE_ENTRY__INIT;
     271                 :            :         struct ifreq ifr;
     272                 :            : 
     273         [ #  # ]:          0 :         if (!(root_ns_mask & CLONE_NEWNET)) {
     274                 :          0 :                 pr_err("Net namespace is required to dump tun link\n");
     275                 :          0 :                 return -1;
     276                 :            :         }
     277                 :            : 
     278         [ #  # ]:          0 :         if (dump_one_reg_file(lfd, id, p))
     279                 :            :                 return -1;
     280                 :            : 
     281                 :          0 :         pr_info("Dumping tun-file %d with id %#x\n", lfd, id);
     282                 :            : 
     283                 :          0 :         tfe.id          = id;
     284                 :          0 :         ret = ioctl(lfd, TUNGETIFF, &ifr);
     285         [ #  # ]:          0 :         if (ret < 0) {
     286         [ #  # ]:          0 :                 if (errno != EBADFD) {
     287                 :          0 :                         pr_perror("Can't dump tun-file device");
     288                 :          0 :                         return -1;
     289                 :            :                 }
     290                 :            : 
     291                 :            :                 /*
     292                 :            :                  * Otherwise this is just opened file with not yet attached
     293                 :            :                  * tun device. Go agead an write the respective entry.
     294                 :            :                  */
     295                 :            :         } else {
     296                 :          0 :                 tfe.netdev = ifr.ifr_name;
     297                 :          0 :                 pr_info("`- attached to device %s (flags %x)\n", tfe.netdev, ifr.ifr_flags);
     298                 :            : 
     299         [ #  # ]:          0 :                 if (ifr.ifr_flags & IFF_DETACH_QUEUE) {
     300                 :          0 :                         tfe.has_detached = true;
     301                 :          0 :                         tfe.detached = true;
     302                 :            :                 }
     303                 :            : 
     304         [ #  # ]:          0 :                 if (dump_tun_link_fd(lfd, tfe.netdev, ifr.ifr_flags) == NULL)
     305                 :            :                         return -1;
     306                 :            :         }
     307                 :            : 
     308                 :          0 :         return pb_write_one(img, &tfe, PB_TUNFILE);
     309                 :            : }
     310                 :            : 
     311                 :            : const struct fdtype_ops tunfile_dump_ops = {
     312                 :            :         .type = FD_TYPES__TUN,
     313                 :            :         .dump = dump_tunfile,
     314                 :            : };
     315                 :            : 
     316                 :            : struct tunfile_info {
     317                 :            :         struct file_desc d;
     318                 :            :         TunfileEntry *tfe;
     319                 :            : };
     320                 :            : 
     321                 :          0 : static int tunfile_open(struct file_desc *d)
     322                 :            : {
     323                 :            :         int fd;
     324                 :            :         struct tunfile_info *ti;
     325                 :            :         struct ifreq ifr;
     326                 :            :         struct tun_link *tl;
     327                 :            : 
     328                 :            :         ti = container_of(d, struct tunfile_info, d);
     329                 :          0 :         fd = open_reg_by_id(ti->tfe->id);
     330         [ #  # ]:          0 :         if (fd < 0)
     331                 :            :                 return -1;
     332                 :            : 
     333         [ #  # ]:          0 :         if (!ti->tfe->netdev)
     334                 :            :                 /* just-opened tun file */
     335                 :            :                 return fd;
     336                 :            : 
     337                 :          0 :         tl = find_tun_link(ti->tfe->netdev);
     338         [ #  # ]:          0 :         if (!tl) {
     339                 :          0 :                 pr_err("No tun device for file %s\n", ti->tfe->netdev);
     340                 :          0 :                 return -1;
     341                 :            :         }
     342                 :            : 
     343                 :            :         memset(&ifr, 0, sizeof(ifr));
     344                 :          0 :         strlcpy(ifr.ifr_name, tl->name, sizeof(ifr.ifr_name));
     345                 :          0 :         ifr.ifr_flags = tl->rst.flags;
     346                 :            : 
     347         [ #  # ]:          0 :         if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
     348                 :          0 :                 pr_perror("Can't attach tunfile to device");
     349                 :          0 :                 goto err;
     350                 :            :         }
     351                 :            : 
     352 [ #  # ][ #  # ]:          0 :         if (ti->tfe->has_detached && ti->tfe->detached) {
     353                 :          0 :                 pr_info("Detaching from %s queue\n", ti->tfe->netdev);
     354                 :          0 :                 ifr.ifr_flags = IFF_DETACH_QUEUE;
     355         [ #  # ]:          0 :                 if (ioctl(fd, TUNSETQUEUE, &ifr) < 0) {
     356                 :          0 :                         pr_perror("Can't detach queue");
     357                 :          0 :                         goto err;
     358                 :            :                 }
     359                 :            :         }
     360                 :            : 
     361         [ #  # ]:          0 :         if (!(tl->rst.flags & IFF_PERSIST)) {
     362                 :          0 :                 pr_info("Dropping persistency for %s\n", tl->name);
     363         [ #  # ]:          0 :                 if (ioctl(fd, TUNSETPERSIST, 0) < 0) {
     364                 :          0 :                         pr_perror("Error dropping persistency");
     365                 :          0 :                         goto err;
     366                 :            :                 }
     367                 :            :         }
     368                 :            : 
     369                 :          0 :         return fd;
     370                 :            : 
     371                 :            : err:
     372                 :          0 :         close(fd);
     373                 :          0 :         return -1;
     374                 :            : }
     375                 :            : 
     376                 :            : static struct file_desc_ops tunfile_desc_ops = {
     377                 :            :         .type = FD_TYPES__TUN,
     378                 :            :         .open = tunfile_open,
     379                 :            : };
     380                 :            : 
     381                 :          0 : static int collect_one_tunfile(void *o, ProtobufCMessage *base)
     382                 :            : {
     383                 :            :         struct tunfile_info *ti = o;
     384                 :            : 
     385                 :          0 :         ti->tfe = pb_msg(base, TunfileEntry);
     386                 :          0 :         file_desc_add(&ti->d, ti->tfe->id, &tunfile_desc_ops);
     387                 :            : 
     388                 :          0 :         pr_info("Collected %s tunfile\n", ti->tfe->netdev);
     389                 :            : 
     390                 :          0 :         return 0;
     391                 :            : }
     392                 :            : 
     393                 :            : struct collect_image_info tunfile_cinfo = {
     394                 :            :         .fd_type = CR_FD_TUNFILE,
     395                 :            :         .pb_type = PB_TUNFILE,
     396                 :            :         .priv_size = sizeof(struct tunfile_info),
     397                 :            :         .collect = collect_one_tunfile,
     398                 :            :         .flags = COLLECT_OPTIONAL,
     399                 :            : };
     400                 :            : 
     401                 :          0 : int dump_tun_link(NetDeviceEntry *nde, struct cr_fdset *fds)
     402                 :            : {
     403                 :          0 :         TunLinkEntry tle = TUN_LINK_ENTRY__INIT;
     404                 :            :         char spath[64];
     405                 :            :         char buf[64];
     406                 :            :         int ret = 0;
     407                 :            :         struct tun_link *tl;
     408                 :            : 
     409                 :          0 :         sprintf(spath, "class/net/%s/tun_flags", nde->name);
     410                 :          0 :         ret |= read_ns_sys_file(spath, buf, sizeof(buf));
     411                 :          0 :         tle.flags = strtol(buf, NULL, 0);
     412                 :            : 
     413                 :          0 :         sprintf(spath, "class/net/%s/owner", nde->name);
     414                 :          0 :         ret |= read_ns_sys_file(spath, buf, sizeof(buf));
     415                 :          0 :         tle.owner = strtol(buf, NULL, 10);
     416                 :            : 
     417                 :          0 :         sprintf(spath, "class/net/%s/group", nde->name);
     418                 :          0 :         ret |= read_ns_sys_file(spath, buf, sizeof(buf));
     419                 :          0 :         tle.group = strtol(buf, NULL, 10);
     420                 :            : 
     421         [ #  # ]:          0 :         if (ret < 0)
     422                 :            :                 return ret;
     423                 :            : 
     424                 :          0 :         tl = get_tun_link_fd(nde->name, tle.flags);
     425         [ #  # ]:          0 :         if (!tl)
     426                 :            :                 return ret;
     427                 :            : 
     428                 :          0 :         tle.vnethdr = tl->dmp.vnethdr;
     429                 :          0 :         tle.sndbuf = tl->dmp.sndbuf;
     430                 :            : 
     431                 :          0 :         nde->tun = &tle;
     432                 :          0 :         return write_netdev_img(nde, fds);
     433                 :            : }
     434                 :            : 
     435                 :          0 : int restore_one_tun(NetDeviceEntry *nde, int nlsk)
     436                 :            : {
     437                 :            :         int fd, ret = -1, aux;
     438                 :            : 
     439         [ #  # ]:          0 :         if (!nde->tun) {
     440                 :          0 :                 pr_err("Corrupted TUN link entry %x\n", nde->ifindex);
     441                 :          0 :                 return -1;
     442                 :            :         }
     443                 :            : 
     444                 :          0 :         pr_info("Restoring tun device %s\n", nde->name);
     445                 :            : 
     446                 :          0 :         fd = open_tun_dev(nde->name, nde->ifindex, nde->tun->flags);
     447         [ #  # ]:          0 :         if (fd < 0)
     448                 :            :                 return -1;
     449                 :            : 
     450                 :          0 :         aux = nde->tun->owner;
     451 [ #  # ][ #  # ]:          0 :         if ((aux != -1) && ioctl(fd, TUNSETOWNER, aux) < 0) {
     452                 :          0 :                 pr_perror("Can't set owner");
     453                 :          0 :                 goto out;
     454                 :            :         }
     455                 :            : 
     456                 :          0 :         aux = nde->tun->group;
     457 [ #  # ][ #  # ]:          0 :         if ((aux != -1) && ioctl(fd, TUNSETGROUP, aux) < 0) {
     458                 :          0 :                 pr_perror("Can't set group");
     459                 :          0 :                 goto out;
     460                 :            :         }
     461                 :            : 
     462                 :          0 :         aux = nde->tun->sndbuf;
     463         [ #  # ]:          0 :         if (ioctl(fd, TUNSETSNDBUF, &aux) < 0) {
     464                 :          0 :                 pr_perror("Can't set sndbuf");
     465                 :          0 :                 goto out;
     466                 :            :         }
     467                 :            : 
     468                 :          0 :         aux = nde->tun->vnethdr;
     469         [ #  # ]:          0 :         if (ioctl(fd, TUNSETVNETHDRSZ, &aux) < 0) {
     470                 :          0 :                 pr_perror("Can't set vnethdr");
     471                 :          0 :                 goto out;
     472                 :            :         }
     473                 :            : 
     474                 :            :         /*
     475                 :            :          * Set this device persistent anyway and schedule
     476                 :            :          * the persistence drop if it should not be such.
     477                 :            :          * The first _real_ opener will do it.
     478                 :            :          */
     479                 :            : 
     480         [ #  # ]:          0 :         if (ioctl(fd, TUNSETPERSIST, 1)) {
     481                 :          0 :                 pr_perror("Can't make tun device persistent");
     482                 :          0 :                 goto out;
     483                 :            :         }
     484                 :            : 
     485         [ #  # ]:          0 :         if (restore_link_parms(nde, nlsk)) {
     486                 :          0 :                 pr_err("Error restoring %s link params\n", nde->name);
     487                 :          0 :                 goto out;
     488                 :            :         }
     489                 :            : 
     490                 :          0 :         ret = list_tun_link(nde);
     491                 :            : out:
     492                 :          0 :         close(fd);
     493                 :          0 :         return ret;
     494                 :            : }

Generated by: LCOV version 1.9