Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/lib/brand/lx/lx_init/lxinit.c
          +++ new/usr/src/lib/brand/lx/lx_init/lxinit.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2015 Joyent, Inc.
  24   24   */
  25   25  
  26   26  /*
  27   27   * lxinit performs zone-specific initialization prior to handing control to the
  28   28   * guest Linux init.  This primarily consists of:
  29   29   *
  30   30   * - Starting ipmgmtd
  31   31   * - Configuring network interfaces
  32   32   * - Adding a default route
  33   33   */
  34   34  
  35   35  #include <ctype.h>
  36   36  #include <errno.h>
  37   37  #include <fcntl.h>
  38   38  #include <libgen.h>
  39   39  #include <limits.h>
  40   40  #include <net/if.h>
  41   41  #include <stdarg.h>
  42   42  #include <stdio.h>
  43   43  #include <stdlib.h>
  44   44  #include <string.h>
  45   45  #include <strings.h>
  46   46  #include <stropts.h>
  47   47  #include <sys/ioccom.h>
  48   48  #include <sys/stat.h>
  49   49  #include <sys/systeminfo.h>
  50   50  #include <sys/sockio.h>
  51   51  #include <sys/types.h>
  52   52  #include <sys/wait.h>
  53   53  #include <sys/varargs.h>
  54   54  #include <unistd.h>
  55   55  #include <libintl.h>
  56   56  #include <locale.h>
  57   57  #include <libcmdutils.h>
  58   58  
  59   59  #include <netinet/dhcp.h>
  60   60  #include <dhcpagent_util.h>
  61   61  #include <dhcpagent_ipc.h>
  62   62  
  63   63  #include <arpa/inet.h>
  64   64  #include <net/route.h>
  65   65  #include <libipadm.h>
  66   66  #include <libzonecfg.h>
  67   67  #include <libinetutil.h>
  68   68  #include <sys/lx_brand.h>
  69   69  
  70   70  #include "run_command.h"
  71   71  
  72   72  static void lxi_err(char *msg, ...) __NORETURN;
  73   73  static void lxi_err(char *msg, ...);
  74   74  
  75   75  #define IPMGMTD_PATH    "/lib/inet/ipmgmtd"
  76   76  #define IN_NDPD_PATH    "/usr/lib/inet/in.ndpd"
  77   77  
  78   78  #define PREFIX_LOG_WARN "lx_init warn: "
  79   79  #define PREFIX_LOG_ERR  "lx_init err: "
  80   80  
  81   81  #define RTMBUFSZ        (sizeof (struct rt_msghdr) + \
  82   82                  (3 * sizeof (struct sockaddr_in)))
  83   83  
  84   84  ipadm_handle_t iph;
  85   85  
  86   86  static void
  87   87  lxi_err(char *msg, ...)
  88   88  {
  89   89          char buf[1024];
  90   90          int len;
  91   91          va_list ap;
  92   92  
  93   93          va_start(ap, msg);
  94   94          /*LINTED*/
  95   95          len = vsnprintf(buf, sizeof (buf), msg, ap);
  
    | 
      ↓ open down ↓ | 
    95 lines elided | 
    
      ↑ open up ↑ | 
  
  96   96          va_end(ap);
  97   97  
  98   98          (void) write(1, PREFIX_LOG_ERR, strlen(PREFIX_LOG_ERR));
  99   99          (void) write(1, buf, len);
 100  100          (void) write(1, "\n", 1);
 101  101  
 102  102          /*
 103  103           * Since a non-zero exit will cause the zone to reboot, a pause here
 104  104           * will prevent a mis-configured zone from spinning in a reboot loop.
 105  105           */
 106      -        pause();
      106 +        (void) pause();
 107  107          exit(1);
 108  108          /*NOTREACHED*/
 109  109  }
 110  110  
 111  111  static void
 112  112  lxi_warn(char *msg, ...)
 113  113  {
 114  114          char buf[1024];
 115  115          int len;
 116  116          va_list ap;
 117  117  
 118  118          va_start(ap, msg);
 119  119          /*LINTED*/
 120  120          len = vsnprintf(buf, sizeof (buf), msg, ap);
 121  121          va_end(ap);
 122  122  
 123  123          (void) write(1, PREFIX_LOG_WARN, strlen(PREFIX_LOG_WARN));
 124  124          (void) write(1, buf, len);
 125  125          (void) write(1, "\n", 1);
 126  126  }
 127  127  
 128  128  static void
 129  129  lxi_log_open()
 130  130  {
 131  131          int fd = open("/dev/console", O_WRONLY);
 132  132  
 133  133          if (fd < 0) {
 134  134                  /* hard to log at this point... */
 135  135                  exit(1);
 136  136          } else if (fd != 1) {
 137  137                  /*
 138  138                   * Use stdout as the log fd.  Init should start with no files
 139  139                   * open, so we should be required to perform this relocation
 140  140                   * every time.
 141  141                   */
 142  142                  if (dup2(fd, 1) != 1) {
 143  143                          exit(1);
 144  144                  }
 145  145          }
 146  146  }
 147  147  
 148  148  static void
 149  149  lxi_log_close()
 150  150  {
 151  151          (void) close(0);
 152  152          (void) close(1);
 153  153  }
 154  154  
 155  155  static zone_dochandle_t
 156  156  lxi_config_open()
 157  157  {
 158  158          zoneid_t zoneid;
 159  159          char zonename[ZONENAME_MAX];
 160  160          zone_dochandle_t handle;
 161  161          zone_iptype_t iptype;
 162  162          int res;
 163  163  
 164  164          zoneid = getzoneid();
 165  165          if (getzonenamebyid(zoneid, zonename, sizeof (zonename)) < 0) {
 166  166                  lxi_err("could not determine zone name");
 167  167          }
 168  168  
 169  169          if ((handle = zonecfg_init_handle()) == NULL)
 170  170                  lxi_err("internal libzonecfg.so.1 error", 0);
 171  171  
 172  172          if ((res = zonecfg_get_handle(zonename, handle)) != Z_OK) {
 173  173                  zonecfg_fini_handle(handle);
 174  174                  lxi_err("could not locate zone config %d", res);
 175  175          }
 176  176  
 177  177          /*
 178  178           * Only exclusive stack is supported.
 179  179           */
 180  180          if (zonecfg_get_iptype(handle, &iptype) != Z_OK ||
 181  181              iptype != ZS_EXCLUSIVE) {
 182  182                  zonecfg_fini_handle(handle);
 183  183                  lxi_err("lx zones do not support shared IP stacks");
 184  184          }
 185  185  
 186  186          return (handle);
 187  187  
 188  188  }
 189  189  
 190  190  static int
 191  191  zone_find_attr(struct zone_res_attrtab *attrs, const char *name,
 192  192      const char **result)
 193  193  {
 194  194          while (attrs != NULL) {
  
    | 
      ↓ open down ↓ | 
    78 lines elided | 
    
      ↑ open up ↑ | 
  
 195  195                  if (strncmp(attrs->zone_res_attr_name, name,
 196  196                      MAXNAMELEN) == 0) {
 197  197                          *result = attrs->zone_res_attr_value;
 198  198                          return (0);
 199  199                  }
 200  200                  attrs = attrs->zone_res_attr_next;
 201  201          }
 202  202          return (-1);
 203  203  }
 204  204  
 205      -void
      205 +static void
 206  206  lxi_svc_start(char *name, char *path, char *fmri)
 207  207  {
 208  208          pid_t pid;
 209  209          int status;
 210      -        char *const argv[] = {
 211      -                name,
      210 +        char *argv[] = {
      211 +                NULL,
 212  212                  NULL
 213  213          };
 214      -        char *const envp[] = {
 215      -                fmri,
      214 +        char *envp[] = {
      215 +                NULL,
 216  216                  NULL
 217  217          };
      218 +        argv[0] = name;
      219 +        envp[0] = fmri;
 218  220  
 219  221          pid = fork();
 220  222          if (pid == -1) {
 221  223                  lxi_err("fork() failed: %s", strerror(errno));
 222  224          }
 223  225  
 224  226          if (pid == 0) {
 225  227                  /* child */
 226  228                  const char *zroot = zone_get_nroot();
 227  229                  char cmd[MAXPATHLEN];
 228  230  
 229  231                  /*
 230  232                   * Construct the full path to the binary, including the native
 231  233                   * system root (e.g. "/native") if in use for this zone:
 232  234                   */
 233  235                  (void) snprintf(cmd, sizeof (cmd), "%s%s", zroot != NULL ?
 234  236                      zroot : "", path);
 235  237  
 236      -                execve(cmd, argv, envp);
      238 +                (void) execve(cmd, argv, envp);
 237  239  
 238  240                  lxi_err("execve(%s) failed: %s", cmd, strerror(errno));
 239  241                  /* NOTREACHED */
 240  242          }
 241  243  
 242  244          /* parent */
 243      -        while (wait(&status) != pid) {
 244      -                /* EMPTY */;
 245      -        }
      245 +        while (wait(&status) != pid)
      246 +                ;
 246  247  
 247  248          if (WIFEXITED(status)) {
 248  249                  if (WEXITSTATUS(status) != 0) {
 249  250                          lxi_err("%s[%d] exited: %d", name,
 250  251                              (int)pid, WEXITSTATUS(status));
 251  252                  }
 252  253          } else if (WIFSIGNALED(status)) {
 253  254                  lxi_err("%s[%d] died on signal: %d", name,
 254  255                      (int)pid, WTERMSIG(status));
 255  256          } else {
 256  257                  lxi_err("%s[%d] failed in unknown way", name,
 257  258                      (int)pid);
 258  259          }
 259  260  }
 260  261  
 261  262  void
 262  263  lxi_net_ipmgmtd_start()
 263  264  {
 264  265          lxi_svc_start("ipmgmtd", IPMGMTD_PATH,
 265  266              "SMF_FMRI=svc:/network/ip-interface-management:default");
 266  267  }
 267  268  
 268  269  void
 269  270  lxi_net_ndpd_start()
 270  271  {
 271  272          lxi_svc_start("in.ndpd", IN_NDPD_PATH,
 272  273              "SMF_FMRI=svc:/network/routing/ndp:default");
 273  274  }
 274  275  
 275  276  
 276  277  static void
 277  278  lxi_net_ipadm_open()
 278  279  {
 279  280          ipadm_status_t status;
 280  281  
 281  282          if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS) {
 282  283                  lxi_err("Error opening ipadm handle: %s",
 283  284                      ipadm_status2str(status));
 284  285          }
 285  286  }
 286  287  
 287  288  static void
 288  289  lxi_net_ipadm_close()
 289  290  {
 290  291          ipadm_close(iph);
 291  292  }
 292  293  
 293  294  void
 294  295  lxi_net_plumb(const char *iface)
 295  296  {
 296  297          ipadm_status_t status;
 297  298          char ifbuf[LIFNAMSIZ];
 298  299  
 299  300          /* ipadm_create_if stomps on ifbuf, so create a copy: */
 300  301          (void) strncpy(ifbuf, iface, sizeof (ifbuf));
 301  302  
 302  303          if ((status = ipadm_create_if(iph, ifbuf, AF_INET, IPADM_OPT_ACTIVE))
 303  304              != IPADM_SUCCESS) {
 304  305                  lxi_err("ipadm_create_if error %d: %s/v4: %s",
 305  306                      status, iface, ipadm_status2str(status));
 306  307          }
 307  308  
 308  309          if ((status = ipadm_create_if(iph, ifbuf, AF_INET6, IPADM_OPT_ACTIVE))
 309  310              != IPADM_SUCCESS) {
 310  311                  lxi_err("ipadm_create_if error %d: %s/v6: %s",
 311  312                      status, iface, ipadm_status2str(status));
 312  313          }
 313  314  }
 314  315  
 315  316  static int
 316  317  lxi_getif(int af, char *iface, int len, boolean_t first_ipv4_configured)
 317  318  {
 318  319          struct lifreq lifr;
 319  320          int s = socket(af, SOCK_DGRAM, 0);
 320  321          if (s < 0) {
 321  322                  lxi_warn("socket error %d: bringing up %s: %s",
 322  323                      errno, iface, strerror(errno));
 323  324                  return (-1);
 324  325          }
 325  326  
 326  327          /*
 327  328           * We need a new logical interface for every IP address we add, except
 328  329           * for the very first IPv4 address.
 329  330           */
 330  331          if (af == AF_INET6 || first_ipv4_configured) {
 331  332                  (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
 332  333                  (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
 333  334                  if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
 334  335                          if (close(s) != 0) {
 335  336                                  lxi_warn("failed to close socket: %s\n",
 336  337                                      strerror(errno));
 337  338                          }
 338  339                          return (-1);
 339  340                  }
 340  341                  (void) strncpy(iface, lifr.lifr_name, len);
 341  342          }
 342  343  
 343  344          if (close(s) != 0) {
 344  345                  lxi_warn("failed to close socket: %s\n",
 345  346                      strerror(errno));
 346  347          }
 347  348          return (0);
 348  349  }
 349  350  
 350  351  static int
 351  352  lxi_iface_ip(const char *origiface, const char *addr,
 352  353      boolean_t *first_ipv4_configured)
 353  354  {
 354  355          static int addrnum = 0;
 355  356          ipadm_status_t status;
 356  357          ipadm_addrobj_t ipaddr = NULL;
 357  358          char iface[LIFNAMSIZ];
 358  359          char aobjname[IPADM_AOBJSIZ];
 359  360          int af, err = 0;
 360  361  
 361  362          (void) strncpy(iface, origiface, sizeof (iface));
 362  363  
 363  364          af = strstr(addr, ":") == NULL ? AF_INET : AF_INET6;
 364  365          if (lxi_getif(af, iface, sizeof (iface), *first_ipv4_configured) != 0) {
 365  366                  lxi_warn("failed to create new logical interface "
 366  367                      "on %s: %s", origiface, strerror(errno));
 367  368                  return (-1);
 368  369          }
 369  370  
 370  371          (void) snprintf(aobjname, IPADM_AOBJSIZ, "%s/addr%d", iface,
 371  372              addrnum++);
 372  373  
 373  374          if ((status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname,
 374  375              &ipaddr)) != IPADM_SUCCESS) {
 375  376                  lxi_warn("ipadm_create_addrobj error %d: addr %s, "
 376  377                      "interface %s: %s\n", status, addr, iface,
 377  378                      ipadm_status2str(status));
 378  379                  return (-2);
 379  380          }
 380  381  
 381  382          if ((status = ipadm_set_addr(ipaddr, addr, AF_UNSPEC))
 382  383              != IPADM_SUCCESS) {
 383  384                  lxi_warn("ipadm_set_addr error %d: addr %s"
 384  385                      ", interface %s: %s\n", status, addr,
 385  386                      iface, ipadm_status2str(status));
 386  387                  err = -3;
 387  388                  goto done;
 388  389          }
 389  390  
 390  391          if ((status = ipadm_create_addr(iph, ipaddr,
 391  392              IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
 392  393                  lxi_warn("ipadm_create_addr error for %s: %s\n", iface,
 393  394                      ipadm_status2str(status));
 394  395                  err = -4;
 395  396                  goto done;
 396  397          }
 397  398  
 398  399          if (af == AF_INET) {
 399  400                  *first_ipv4_configured = B_TRUE;
 400  401          }
 401  402  
 402  403  done:
 403  404          ipadm_destroy_addrobj(ipaddr);
 404  405          return (err);
 405  406  }
 406  407  
 407  408  static int
 408  409  lxi_iface_dhcp(const char *origiface, boolean_t *first_ipv4_configured)
 409  410  {
 410  411          dhcp_ipc_request_t *dhcpreq = NULL;
 411  412          dhcp_ipc_reply_t *dhcpreply = NULL;
 412  413          int err = 0, timeout = 5;
 413  414          char iface[LIFNAMSIZ];
 414  415  
 415  416          (void) strncpy(iface, origiface, sizeof (iface));
 416  417  
 417  418          if (lxi_getif(AF_INET, iface, sizeof (iface), *first_ipv4_configured)
 418  419              != 0) {
 419  420                  lxi_warn("failed to create new logical interface "
 420  421                      "on %s: %s", origiface, strerror(errno));
 421  422                  return (-1);
 422  423          }
 423  424  
 424  425          if (dhcp_start_agent(timeout) != 0) {
 425  426                  lxi_err("Failed to start dhcpagent\n");
 426  427                  /* NOTREACHED */
 427  428          }
 428  429  
 429  430          dhcpreq = dhcp_ipc_alloc_request(DHCP_START, iface,
 430  431              NULL, 0, DHCP_TYPE_NONE);
 431  432          if (dhcpreq == NULL) {
 432  433                  lxi_warn("Unable to allocate memory "
 433  434                      "to start DHCP on %s\n", iface);
 434  435                  return (-1);
 435  436          }
 436  437  
 437  438          err = dhcp_ipc_make_request(dhcpreq, &dhcpreply, timeout);
 438  439          if (err != 0) {
 439  440                  free(dhcpreq);
 440  441                  lxi_warn("Failed to start DHCP on %s: %s\n", iface,
 441  442                      dhcp_ipc_strerror(err));
 442  443                  return (-1);
 443  444          }
 444  445          err = dhcpreply->return_code;
 445  446          if (err != 0) {
 446  447                  lxi_warn("Failed to start DHCP on %s: %s\n", iface,
 447  448                      dhcp_ipc_strerror(err));
 448  449                  goto done;
 449  450          }
 450  451  
 451  452          *first_ipv4_configured = B_TRUE;
 452  453  
 453  454  done:
 454  455          free(dhcpreq);
 455  456          free(dhcpreply);
 456  457          return (err);
 457  458  }
 458  459  
 459  460  /*
 460  461   * Initialize an IPv6 link-local address on a given interface
 461  462   */
 462  463  static int
 463  464  lxi_iface_ipv6_link_local(const char *iface)
 464  465  {
 465  466          struct lifreq lifr;
 466  467          int s;
 467  468  
 468  469          s = socket(AF_INET6, SOCK_DGRAM, 0);
 469  470          if (s == -1) {
 470  471                  lxi_warn("socket error %d: bringing up %s: %s",
 471  472                      errno, iface, strerror(errno));
 472  473          }
 473  474  
 474  475          (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
 475  476          if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
 476  477                  lxi_warn("SIOCGLIFFLAGS error %d: bringing up %s: %s",
 477  478                      errno, iface, strerror(errno));
 478  479                  return (-1);
 479  480          }
 480  481  
 481  482          lifr.lifr_flags |= IFF_UP;
 482  483          if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
 483  484                  lxi_warn("SIOCSLIFFLAGS error %d: bringing up %s: %s",
 484  485                      errno, iface, strerror(errno));
 485  486                  return (-1);
 486  487          }
  
    | 
      ↓ open down ↓ | 
    231 lines elided | 
    
      ↑ open up ↑ | 
  
 487  488  
 488  489          (void) close(s);
 489  490          return (0);
 490  491  }
 491  492  
 492  493  static int
 493  494  lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
 494  495      const char *gwaddr)
 495  496  {
 496  497          int idx, len, sockfd;
 497      -        char rtbuf[RTMBUFSZ];
      498 +        /* For lint-happy alignment, use a uint32_t array... */
      499 +        uint32_t rtbuf[RTMBUFSZ / sizeof (uint32_t)];
 498  500          struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
 499      -        struct sockaddr_in *dst_sin = (struct sockaddr_in *)
 500      -            (rtbuf + sizeof (struct rt_msghdr));
      501 +        struct sockaddr_in *dst_sin = (struct sockaddr_in *)(rtm + 1);
 501  502          struct sockaddr_in *gw_sin = (struct sockaddr_in *)(dst_sin + 1);
 502  503          struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(gw_sin + 1);
 503  504  
 504  505          (void) bzero(rtm, RTMBUFSZ);
 505  506          rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 506  507          rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
 507  508          rtm->rtm_msglen = sizeof (rtbuf);
 508  509          rtm->rtm_pid = getpid();
 509  510          rtm->rtm_type = RTM_ADD;
 510  511          rtm->rtm_version = RTM_VERSION;
 511  512  
 512  513  
 513  514          /*
 514  515           * The destination and netmask components have already been zeroed,
 515  516           * which represents the default gateway.  If we were passed a more
 516  517           * specific destination network, use that instead.
 517  518           */
 518  519          dst_sin->sin_family = AF_INET;
 519  520          netmask_sin->sin_family = AF_INET;
 520  521          if (dst != NULL) {
 521  522                  struct sockaddr *mask = (struct sockaddr *)netmask_sin;
 522  523  
 523  524                  if ((inet_pton(AF_INET, dst, &(dst_sin->sin_addr))) != 1 ||
 524  525                      plen2mask(dstpfx, AF_INET, mask) != 0) {
 525  526                          lxi_warn("bad destination network %s/%d: %s", dst,
 526  527                              dstpfx, strerror(errno));
 527  528                          return (-1);
 528  529                  }
 529  530          }
 530  531  
 531  532          if ((inet_pton(AF_INET, gwaddr, &(gw_sin->sin_addr))) != 1) {
 532  533                  lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
 533  534                  return (-1);
 534  535          }
 535  536  
 536  537          if (iface != NULL) {
 537  538                  if ((idx = if_nametoindex(iface)) == 0) {
 538  539                          lxi_warn("unable to get interface index for %s: %s\n",
 539  540                              iface, strerror(errno));
 540  541                          return (-1);
 541  542                  }
  
    | 
      ↓ open down ↓ | 
    31 lines elided | 
    
      ↑ open up ↑ | 
  
 542  543                  rtm->rtm_index = idx;
 543  544          }
 544  545  
 545  546          if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
 546  547                  lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
 547  548                  return (-1);
 548  549          }
 549  550  
 550  551          if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
 551  552                  lxi_warn("could not write rtmsg: %s", strerror(errno));
 552      -                close(sockfd);
      553 +                (void) close(sockfd);
 553  554                  return (-1);
 554  555          } else if (len < rtm->rtm_msglen) {
 555  556                  lxi_warn("write() rtmsg incomplete");
 556      -                close(sockfd);
      557 +                (void) close(sockfd);
 557  558                  return (-1);
 558  559          }
 559  560  
 560      -        close(sockfd);
      561 +        (void) close(sockfd);
 561  562          return (0);
 562  563  }
 563  564  
 564  565  static void
 565  566  lxi_net_loopback()
 566  567  {
 567  568          const char *iface = "lo0";
 568  569          boolean_t first_ipv4_configured = B_FALSE;
 569  570  
 570  571          lxi_net_plumb(iface);
 571  572          (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
 572  573          (void) lxi_iface_ipv6_link_local(iface);
 573  574  }
 574  575  
 575      -
 576      -/*
 577      - * This function is used when the "ips" property doesn't exist in a zone's
 578      - * configuration. It may be an older configuration, so we should search for
 579      - * "ip" and "netmask" and convert them into the new format.
 580      - */
 581      -static int
 582      -lxi_get_old_ip(struct zone_res_attrtab *attrs, const char **ipaddrs,
 583      -    char *cidraddr, int len)
 584      -{
 585      -
 586      -        const char *netmask;
 587      -        int prefixlen;
 588      -        struct sockaddr_in mask_sin;
 589      -
 590      -        lxi_warn("Could not find \"ips\" property for zone. Looking "
 591      -            "for older \"ip\" and \"netmask\" properties, instead.");
 592      -
 593      -        if (zone_find_attr(attrs, "ip", ipaddrs) != 0) {
 594      -                return (-1);
 595      -        }
 596      -
 597      -        if (strcmp(*ipaddrs, "dhcp") == 0) {
 598      -                return (0);
 599      -        }
 600      -
 601      -        if (zone_find_attr(attrs, "netmask", &netmask) != 0) {
 602      -                lxi_err("could not find netmask for interface");
 603      -                /* NOTREACHED */
 604      -        }
 605      -
 606      -        /* Convert the netmask to a number */
 607      -        mask_sin.sin_family = AF_INET;
 608      -        if (inet_pton(AF_INET, netmask, &mask_sin.sin_addr) != 1) {
 609      -                lxi_err("invalid netmask address: %s\n",
 610      -                    strerror(errno));
 611      -                /* NOTREACHED */
 612      -        }
 613      -        prefixlen = mask2plen((struct sockaddr *)&mask_sin);
 614      -
 615      -        /*
 616      -         * Write out the IP address in the new format and use
 617      -         * that instead
 618      -         */
 619      -        (void) snprintf(cidraddr, len, "%s/%d", *ipaddrs, prefixlen);
 620      -
 621      -        *ipaddrs = cidraddr;
 622      -        return (0);
 623      -}
 624      -
 625  576  static void
 626  577  lxi_net_setup(zone_dochandle_t handle)
 627  578  {
 628  579          struct zone_nwiftab lookup;
 629  580          boolean_t do_addrconf = B_FALSE;
 630  581  
 631  582          if (zonecfg_setnwifent(handle) != Z_OK)
 632  583                  return;
 633  584          while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
 634  585                  const char *iface = lookup.zone_nwif_physical;
 635  586                  struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
 636  587                  const char *ipaddrs, *primary, *gateway;
 637      -                char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
      588 +                char ipaddrs_copy[MAXNAMELEN], /* cidraddr[BUFSIZ], */
 638  589                      *ipaddr, *tmp, *lasts;
 639  590                  boolean_t first_ipv4_configured = B_FALSE;
 640  591                  boolean_t *ficp = &first_ipv4_configured;
      592 +                boolean_t no_zonecfg;
 641  593  
      594 +                /*
      595 +                 * Regardless of whether we're configured in zonecfg(1M), or
      596 +                 * configured by other means, make sure we plumb every
      597 +                 * physical=<foo> for IPv4 and IPv6.
      598 +                 */
 642  599                  lxi_net_plumb(iface);
 643      -                if (zone_find_attr(attrs, "ips", &ipaddrs) != 0 &&
 644      -                    lxi_get_old_ip(attrs, &ipaddrs, cidraddr, BUFSIZ) != 0) {
 645      -                        lxi_warn("Could not find a valid network configuration "
 646      -                            "for the %s interface", iface);
 647      -                        continue;
      600 +
      601 +                if (zone_find_attr(attrs, "ips", &ipaddrs) != 0 /* &&
      602 +                    lxi_get_old_ip(attrs, &ipaddrs, cidraddr, BUFSIZ) != 0*/) {
      603 +                        /*
      604 +                         * Do not panic.  This interface has no in-zonecfg(1M)
      605 +                         * configuration.  We keep a warning around for now.
      606 +                         */
      607 +                        lxi_warn("Could not find zonecfg(1M) network "
      608 +                            "configuration for the %s interface", iface);
      609 +                        no_zonecfg = B_TRUE;
      610 +                } else {
      611 +                        no_zonecfg = B_FALSE;
 648  612                  }
 649  613  
 650  614                  if (lxi_iface_ipv6_link_local(iface) != 0) {
 651  615                          lxi_warn("unable to bring up link-local address on "
 652  616                              "interface %s", iface);
 653  617                  }
 654  618  
 655  619                  /*
 656      -                 * If we're going to be doing DHCP, we have to do it first since
 657      -                 * dhcpagent doesn't like to operate on non-zero logical
      620 +                 * Every thing else below only happens if we have zonecfg(1M)
      621 +                 * network configuration.
      622 +                 */
      623 +                if (no_zonecfg)
      624 +                        continue;
      625 +
      626 +                /*
      627 +                 * If we're going to be doing DHCP, we have to do it first
      628 +                 * since dhcpagent doesn't like to operate on non-zero logical
 658  629                   * interfaces.
 659  630                   */
 660  631                  if (strstr(ipaddrs, "dhcp") != NULL &&
 661  632                      lxi_iface_dhcp(iface, ficp) != 0) {
 662  633                          lxi_warn("Failed to start DHCP on %s\n", iface);
 663  634                  }
 664  635  
 665  636                  /*
 666  637                   * Copy the ipaddrs string, since strtok_r will write NUL
 667  638                   * characters into it.
 668  639                   */
 669  640                  (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
 670  641                  tmp = ipaddrs_copy;
 671  642  
 672  643                  /*
 673  644                   * Iterate over each IP and then set it up on the interface.
 674  645                   */
 675  646                  while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
 676  647                          tmp = NULL;
 677  648                          if (strcmp(ipaddr, "addrconf") == 0) {
 678  649                                  do_addrconf = B_TRUE;
 679  650                          } else if (strcmp(ipaddr, "dhcp") == 0) {
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
 680  651                                  continue;
 681  652                          } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
 682  653                                  lxi_warn("Unable to add new IP address (%s) "
 683  654                                      "to interface %s", ipaddr, iface);
 684  655                          }
 685  656                  }
 686  657  
 687  658                  if (zone_find_attr(attrs, "primary", &primary) == 0 &&
 688  659                      strncmp(primary, "true", MAXNAMELEN) == 0 &&
 689  660                      zone_find_attr(attrs, "gateway", &gateway) == 0) {
 690      -                        lxi_iface_gateway(iface, NULL, 0, gateway);
      661 +                        if (lxi_iface_gateway(iface, NULL, 0, gateway) != 0) {
      662 +                                lxi_err("default route on %s -> %s failed",
      663 +                                    iface, gateway);
      664 +                        }
 691  665                  }
 692  666          }
 693  667  
 694  668          if (do_addrconf) {
 695  669                  lxi_net_ndpd_start();
 696  670          }
 697  671  
 698  672          (void) zonecfg_endnwifent(handle);
 699  673  }
 700  674  
 701  675  static void
 702  676  lxi_net_static_route(const char *line)
 703  677  {
 704  678          /*
 705  679           * Each static route line is a string of the form:
 706  680           *
 707  681           *      "10.77.77.2|10.1.1.0/24|false"
 708  682           *
 709  683           * i.e. gateway address, destination network, and whether this is
 710  684           * a "link local" route or a next hop route.
 711  685           */
 712  686          custr_t *cu = NULL;
 713  687          char *gw = NULL, *dst = NULL;
 714  688          int pfx = -1;
 715  689          int i;
 716  690  
 717  691          if (custr_alloc(&cu) != 0) {
 718  692                  lxi_err("custr_alloc failure");
 719  693          }
 720  694  
 721  695          for (i = 0; line[i] != '\0'; i++) {
 722  696                  if (gw == NULL) {
 723  697                          if (line[i] == '|') {
 724  698                                  if ((gw = strdup(custr_cstr(cu))) == NULL) {
 725  699                                          lxi_err("strdup failure");
 726  700                                  }
 727  701                                  custr_reset(cu);
 728  702                          } else {
 729  703                                  if (custr_appendc(cu, line[i]) != 0) {
 730  704                                          lxi_err("custr_appendc failure");
 731  705                                  }
 732  706                          }
 733  707                          continue;
 734  708                  }
 735  709  
 736  710                  if (dst == NULL) {
 737  711                          if (line[i] == '/') {
 738  712                                  if ((dst = strdup(custr_cstr(cu))) == NULL) {
 739  713                                          lxi_err("strdup failure");
 740  714                                  }
 741  715                                  custr_reset(cu);
 742  716                          } else {
 743  717                                  if (custr_appendc(cu, line[i]) != 0) {
 744  718                                          lxi_err("custr_appendc failure");
 745  719                                  }
 746  720                          }
 747  721                          continue;
 748  722                  }
 749  723  
 750  724                  if (pfx == -1) {
 751  725                          if (line[i] == '|') {
 752  726                                  pfx = atoi(custr_cstr(cu));
 753  727                                  custr_reset(cu);
 754  728                          } else {
 755  729                                  if (custr_appendc(cu, line[i]) != 0) {
 756  730                                          lxi_err("custr_appendc failure");
 757  731                                  }
 758  732                          }
 759  733                          continue;
 760  734                  }
 761  735  
 762  736                  if (custr_appendc(cu, line[i]) != 0) {
 763  737                          lxi_err("custr_appendc failure");
 764  738                  }
 765  739          }
 766  740  
 767  741          /*
 768  742           * We currently only support "next hop" routes, so ensure that
 769  743           * "linklocal" is false:
 770  744           */
 771  745          if (strcmp(custr_cstr(cu), "false") != 0) {
 772  746                  lxi_warn("invalid static route: %s", line);
 773  747          }
 774  748  
 775  749          if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
 776  750                  lxi_err("failed to add route: %s/%d -> %s", dst, pfx, gw);
 777  751          }
 778  752  
 779  753          custr_free(cu);
 780  754          free(gw);
 781  755          free(dst);
 782  756  }
 783  757  
 784  758  static void
 785  759  lxi_net_static_routes(void)
 786  760  {
 787  761          const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
 788  762          char *const argv[] = { "routeinfo", NULL };
 789  763          char *const envp[] = { NULL };
 790  764          int code;
 791  765          struct stat st;
 792  766          char errbuf[512];
 793  767  
 794  768          if (stat(cmd, &st) != 0 || !S_ISREG(st.st_mode)) {
 795  769                  /*
 796  770                   * This binary is (potentially) shipped from another
 797  771                   * consolidation.  If it does not exist, then the platform does
 798  772                   * not currently support static routes for LX-branded zones.
 799  773                   */
 800  774                  return;
 801  775          }
 802  776  
 803  777          /*
 804  778           * Run the command, firing the callback for each line that it
 805  779           * outputs.  When this function returns, static route processing
 806  780           * is complete.
 807  781           */
 808  782          if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
 809  783              lxi_net_static_route, &code) != 0 || code != 0) {
 810  784                  lxi_err("failed to run \"%s\": %s", cmd, errbuf);
 811  785          }
 812  786  }
 813  787  
 814  788  static void
 815  789  lxi_config_close(zone_dochandle_t handle)
 816  790  {
 817  791          zonecfg_fini_handle(handle);
 818  792  }
 819  793  
 820  794  static void
 821  795  lxi_init_exec(char **argv)
 822  796  {
 823  797          const char *cmd = "/sbin/init";
 824  798          char *const envp[] = { "container=zone", NULL };
  
    | 
      ↓ open down ↓ | 
    124 lines elided | 
    
      ↑ open up ↑ | 
  
 825  799          int e;
 826  800  
 827  801          argv[0] = "init";
 828  802  
 829  803          /*
 830  804           * systemd uses the 'container' env var to determine it is running
 831  805           * inside a container. It only supports a few well-known types and
 832  806           * treats anything else as 'other' but this is enough to make it
 833  807           * behave better inside a zone. See 'detect_container' in systemd.
 834  808           */
 835      -        execve(cmd, argv, envp);
      809 +        (void) execve(cmd, argv, envp);
 836  810          e = errno;
 837  811  
 838  812          /*
 839  813           * Because stdout was closed prior to exec, it must be opened again in
 840  814           * the face of failure to log the error.
 841  815           */
 842  816          lxi_log_open();
 843  817          lxi_err("execve(%s) failed: %s", cmd, strerror(e));
 844  818  }
 845  819  
 846  820  /*ARGSUSED*/
 847  821  int
 848  822  main(int argc, char *argv[])
 849  823  {
 850  824          zone_dochandle_t handle;
 851  825  
 852  826          lxi_log_open();
 853  827  
 854  828          lxi_net_ipmgmtd_start();
 855  829          lxi_net_ipadm_open();
 856  830  
 857  831          handle = lxi_config_open();
 858  832          lxi_net_loopback();
 859  833          lxi_net_setup(handle);
 860  834          lxi_config_close(handle);
 861  835  
 862  836          lxi_net_static_routes();
 863  837  
 864  838          lxi_net_ipadm_close();
 865  839  
 866  840          lxi_log_close();
 867  841  
 868  842          lxi_init_exec(argv);
 869  843  
 870  844          /* NOTREACHED */
 871  845          return (0);
 872  846  }
  
    | 
      ↓ open down ↓ | 
    27 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX