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