Print this page




  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 }


 185 
 186         return (handle);
 187 
 188 }
 189 
 190 static int
 191 zone_find_attr(struct zone_res_attrtab *attrs, const char *name,
 192     const char **result)
 193 {
 194         while (attrs != NULL) {
 195                 if (strncmp(attrs->zone_res_attr_name, name,
 196                     MAXNAMELEN) == 0) {
 197                         *result = attrs->zone_res_attr_value;
 198                         return (0);
 199                 }
 200                 attrs = attrs->zone_res_attr_next;
 201         }
 202         return (-1);
 203 }
 204 
 205 void
 206 lxi_svc_start(char *name, char *path, char *fmri)
 207 {
 208         pid_t pid;
 209         int status;
 210         char *const argv[] = {
 211                 name,
 212                 NULL
 213         };
 214         char *const envp[] = {
 215                 fmri,
 216                 NULL
 217         };


 218 
 219         pid = fork();
 220         if (pid == -1) {
 221                 lxi_err("fork() failed: %s", strerror(errno));
 222         }
 223 
 224         if (pid == 0) {
 225                 /* child */
 226                 const char *zroot = zone_get_nroot();
 227                 char cmd[MAXPATHLEN];
 228 
 229                 /*
 230                  * Construct the full path to the binary, including the native
 231                  * system root (e.g. "/native") if in use for this zone:
 232                  */
 233                 (void) snprintf(cmd, sizeof (cmd), "%s%s", zroot != NULL ?
 234                     zroot : "", path);
 235 
 236                 execve(cmd, argv, envp);
 237 
 238                 lxi_err("execve(%s) failed: %s", cmd, strerror(errno));
 239                 /* NOTREACHED */
 240         }
 241 
 242         /* parent */
 243         while (wait(&status) != pid) {
 244                 /* EMPTY */;
 245         }
 246 
 247         if (WIFEXITED(status)) {
 248                 if (WEXITSTATUS(status) != 0) {
 249                         lxi_err("%s[%d] exited: %d", name,
 250                             (int)pid, WEXITSTATUS(status));
 251                 }
 252         } else if (WIFSIGNALED(status)) {
 253                 lxi_err("%s[%d] died on signal: %d", name,
 254                     (int)pid, WTERMSIG(status));
 255         } else {
 256                 lxi_err("%s[%d] failed in unknown way", name,
 257                     (int)pid);
 258         }
 259 }
 260 
 261 void
 262 lxi_net_ipmgmtd_start()
 263 {
 264         lxi_svc_start("ipmgmtd", IPMGMTD_PATH,
 265             "SMF_FMRI=svc:/network/ip-interface-management:default");


 477                     errno, iface, strerror(errno));
 478                 return (-1);
 479         }
 480 
 481         lifr.lifr_flags |= IFF_UP;
 482         if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
 483                 lxi_warn("SIOCSLIFFLAGS error %d: bringing up %s: %s",
 484                     errno, iface, strerror(errno));
 485                 return (-1);
 486         }
 487 
 488         (void) close(s);
 489         return (0);
 490 }
 491 
 492 static int
 493 lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
 494     const char *gwaddr)
 495 {
 496         int idx, len, sockfd;
 497         char rtbuf[RTMBUFSZ];

 498         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 *gw_sin = (struct sockaddr_in *)(dst_sin + 1);
 502         struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(gw_sin + 1);
 503 
 504         (void) bzero(rtm, RTMBUFSZ);
 505         rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 506         rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
 507         rtm->rtm_msglen = sizeof (rtbuf);
 508         rtm->rtm_pid = getpid();
 509         rtm->rtm_type = RTM_ADD;
 510         rtm->rtm_version = RTM_VERSION;
 511 
 512 
 513         /*
 514          * The destination and netmask components have already been zeroed,
 515          * which represents the default gateway.  If we were passed a more
 516          * specific destination network, use that instead.
 517          */
 518         dst_sin->sin_family = AF_INET;
 519         netmask_sin->sin_family = AF_INET;
 520         if (dst != NULL) {


 532                 lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
 533                 return (-1);
 534         }
 535 
 536         if (iface != NULL) {
 537                 if ((idx = if_nametoindex(iface)) == 0) {
 538                         lxi_warn("unable to get interface index for %s: %s\n",
 539                             iface, strerror(errno));
 540                         return (-1);
 541                 }
 542                 rtm->rtm_index = idx;
 543         }
 544 
 545         if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
 546                 lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
 547                 return (-1);
 548         }
 549 
 550         if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
 551                 lxi_warn("could not write rtmsg: %s", strerror(errno));
 552                 close(sockfd);
 553                 return (-1);
 554         } else if (len < rtm->rtm_msglen) {
 555                 lxi_warn("write() rtmsg incomplete");
 556                 close(sockfd);
 557                 return (-1);
 558         }
 559 
 560         close(sockfd);
 561         return (0);
 562 }
 563 
 564 static void
 565 lxi_net_loopback()
 566 {
 567         const char *iface = "lo0";
 568         boolean_t first_ipv4_configured = B_FALSE;
 569 
 570         lxi_net_plumb(iface);
 571         (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
 572         (void) lxi_iface_ipv6_link_local(iface);
 573 }
 574 
 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 static void
 626 lxi_net_setup(zone_dochandle_t handle)
 627 {
 628         struct zone_nwiftab lookup;
 629         boolean_t do_addrconf = B_FALSE;
 630 
 631         if (zonecfg_setnwifent(handle) != Z_OK)
 632                 return;
 633         while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
 634                 const char *iface = lookup.zone_nwif_physical;
 635                 struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
 636                 const char *ipaddrs, *primary, *gateway;
 637                 char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
 638                     *ipaddr, *tmp, *lasts;
 639                 boolean_t first_ipv4_configured = B_FALSE;
 640                 boolean_t *ficp = &first_ipv4_configured;

 641 





 642                 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;







 648                 }
 649 
 650                 if (lxi_iface_ipv6_link_local(iface) != 0) {
 651                         lxi_warn("unable to bring up link-local address on "
 652                             "interface %s", iface);
 653                 }
 654 
 655                 /*
 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







 658                  * interfaces.
 659                  */
 660                 if (strstr(ipaddrs, "dhcp") != NULL &&
 661                     lxi_iface_dhcp(iface, ficp) != 0) {
 662                         lxi_warn("Failed to start DHCP on %s\n", iface);
 663                 }
 664 
 665                 /*
 666                  * Copy the ipaddrs string, since strtok_r will write NUL
 667                  * characters into it.
 668                  */
 669                 (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
 670                 tmp = ipaddrs_copy;
 671 
 672                 /*
 673                  * Iterate over each IP and then set it up on the interface.
 674                  */
 675                 while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
 676                         tmp = NULL;
 677                         if (strcmp(ipaddr, "addrconf") == 0) {
 678                                 do_addrconf = B_TRUE;
 679                         } else if (strcmp(ipaddr, "dhcp") == 0) {
 680                                 continue;
 681                         } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
 682                                 lxi_warn("Unable to add new IP address (%s) "
 683                                     "to interface %s", ipaddr, iface);
 684                         }
 685                 }
 686 
 687                 if (zone_find_attr(attrs, "primary", &primary) == 0 &&
 688                     strncmp(primary, "true", MAXNAMELEN) == 0 &&
 689                     zone_find_attr(attrs, "gateway", &gateway) == 0) {
 690                         lxi_iface_gateway(iface, NULL, 0, gateway);


 691                 }
 692         }

 693 
 694         if (do_addrconf) {
 695                 lxi_net_ndpd_start();
 696         }
 697 
 698         (void) zonecfg_endnwifent(handle);
 699 }
 700 
 701 static void
 702 lxi_net_static_route(const char *line)
 703 {
 704         /*
 705          * Each static route line is a string of the form:
 706          *
 707          *      "10.77.77.2|10.1.1.0/24|false"
 708          *
 709          * i.e. gateway address, destination network, and whether this is
 710          * a "link local" route or a next hop route.
 711          */
 712         custr_t *cu = NULL;


 815 lxi_config_close(zone_dochandle_t handle)
 816 {
 817         zonecfg_fini_handle(handle);
 818 }
 819 
 820 static void
 821 lxi_init_exec(char **argv)
 822 {
 823         const char *cmd = "/sbin/init";
 824         char *const envp[] = { "container=zone", NULL };
 825         int e;
 826 
 827         argv[0] = "init";
 828 
 829         /*
 830          * systemd uses the 'container' env var to determine it is running
 831          * inside a container. It only supports a few well-known types and
 832          * treats anything else as 'other' but this is enough to make it
 833          * behave better inside a zone. See 'detect_container' in systemd.
 834          */
 835         execve(cmd, argv, envp);
 836         e = errno;
 837 
 838         /*
 839          * Because stdout was closed prior to exec, it must be opened again in
 840          * the face of failure to log the error.
 841          */
 842         lxi_log_open();
 843         lxi_err("execve(%s) failed: %s", cmd, strerror(e));
 844 }
 845 
 846 /*ARGSUSED*/
 847 int
 848 main(int argc, char *argv[])
 849 {
 850         zone_dochandle_t handle;
 851 
 852         lxi_log_open();
 853 
 854         lxi_net_ipmgmtd_start();
 855         lxi_net_ipadm_open();


  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         (void) 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 }


 185 
 186         return (handle);
 187 
 188 }
 189 
 190 static int
 191 zone_find_attr(struct zone_res_attrtab *attrs, const char *name,
 192     const char **result)
 193 {
 194         while (attrs != NULL) {
 195                 if (strncmp(attrs->zone_res_attr_name, name,
 196                     MAXNAMELEN) == 0) {
 197                         *result = attrs->zone_res_attr_value;
 198                         return (0);
 199                 }
 200                 attrs = attrs->zone_res_attr_next;
 201         }
 202         return (-1);
 203 }
 204 
 205 static void
 206 lxi_svc_start(char *name, char *path, char *fmri)
 207 {
 208         pid_t pid;
 209         int status;
 210         char *argv[] = {
 211                 NULL,
 212                 NULL
 213         };
 214         char *envp[] = {
 215                 NULL,
 216                 NULL
 217         };
 218         argv[0] = name;
 219         envp[0] = fmri;
 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                 (void) 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                 ;

 247 
 248         if (WIFEXITED(status)) {
 249                 if (WEXITSTATUS(status) != 0) {
 250                         lxi_err("%s[%d] exited: %d", name,
 251                             (int)pid, WEXITSTATUS(status));
 252                 }
 253         } else if (WIFSIGNALED(status)) {
 254                 lxi_err("%s[%d] died on signal: %d", name,
 255                     (int)pid, WTERMSIG(status));
 256         } else {
 257                 lxi_err("%s[%d] failed in unknown way", name,
 258                     (int)pid);
 259         }
 260 }
 261 
 262 void
 263 lxi_net_ipmgmtd_start()
 264 {
 265         lxi_svc_start("ipmgmtd", IPMGMTD_PATH,
 266             "SMF_FMRI=svc:/network/ip-interface-management:default");


 478                     errno, iface, strerror(errno));
 479                 return (-1);
 480         }
 481 
 482         lifr.lifr_flags |= IFF_UP;
 483         if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
 484                 lxi_warn("SIOCSLIFFLAGS error %d: bringing up %s: %s",
 485                     errno, iface, strerror(errno));
 486                 return (-1);
 487         }
 488 
 489         (void) close(s);
 490         return (0);
 491 }
 492 
 493 static int
 494 lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
 495     const char *gwaddr)
 496 {
 497         int idx, len, sockfd;
 498         /* For lint-happy alignment, use a uint32_t array... */
 499         uint32_t rtbuf[RTMBUFSZ / sizeof (uint32_t)];
 500         struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
 501         struct sockaddr_in *dst_sin = (struct sockaddr_in *)(rtm + 1);

 502         struct sockaddr_in *gw_sin = (struct sockaddr_in *)(dst_sin + 1);
 503         struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(gw_sin + 1);
 504 
 505         (void) bzero(rtm, RTMBUFSZ);
 506         rtm->rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
 507         rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
 508         rtm->rtm_msglen = sizeof (rtbuf);
 509         rtm->rtm_pid = getpid();
 510         rtm->rtm_type = RTM_ADD;
 511         rtm->rtm_version = RTM_VERSION;
 512 
 513 
 514         /*
 515          * The destination and netmask components have already been zeroed,
 516          * which represents the default gateway.  If we were passed a more
 517          * specific destination network, use that instead.
 518          */
 519         dst_sin->sin_family = AF_INET;
 520         netmask_sin->sin_family = AF_INET;
 521         if (dst != NULL) {


 533                 lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
 534                 return (-1);
 535         }
 536 
 537         if (iface != NULL) {
 538                 if ((idx = if_nametoindex(iface)) == 0) {
 539                         lxi_warn("unable to get interface index for %s: %s\n",
 540                             iface, strerror(errno));
 541                         return (-1);
 542                 }
 543                 rtm->rtm_index = idx;
 544         }
 545 
 546         if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
 547                 lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
 548                 return (-1);
 549         }
 550 
 551         if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
 552                 lxi_warn("could not write rtmsg: %s", strerror(errno));
 553                 (void) close(sockfd);
 554                 return (-1);
 555         } else if (len < rtm->rtm_msglen) {
 556                 lxi_warn("write() rtmsg incomplete");
 557                 (void) close(sockfd);
 558                 return (-1);
 559         }
 560 
 561         (void) close(sockfd);
 562         return (0);
 563 }
 564 
 565 static void
 566 lxi_net_loopback()
 567 {
 568         const char *iface = "lo0";
 569         boolean_t first_ipv4_configured = B_FALSE;
 570 
 571         lxi_net_plumb(iface);
 572         (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
 573         (void) lxi_iface_ipv6_link_local(iface);
 574 }
 575 


















































 576 static void
 577 lxi_net_setup(zone_dochandle_t handle)
 578 {
 579         struct zone_nwiftab lookup;
 580         boolean_t do_addrconf = B_FALSE;
 581 
 582         if (zonecfg_setnwifent(handle) != Z_OK)
 583                 return;
 584         while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
 585                 const char *iface = lookup.zone_nwif_physical;
 586                 struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
 587                 const char *ipaddrs, *primary, *gateway;
 588                 char ipaddrs_copy[MAXNAMELEN], /* cidraddr[BUFSIZ], */
 589                     *ipaddr, *tmp, *lasts;
 590                 boolean_t first_ipv4_configured = B_FALSE;
 591                 boolean_t *ficp = &first_ipv4_configured;
 592                 boolean_t no_zonecfg;
 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                  */
 599                 lxi_net_plumb(iface);
 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;
 612                 }
 613 
 614                 if (lxi_iface_ipv6_link_local(iface) != 0) {
 615                         lxi_warn("unable to bring up link-local address on "
 616                             "interface %s", iface);
 617                 }
 618 
 619                 /*
 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
 629                  * interfaces.
 630                  */
 631                 if (strstr(ipaddrs, "dhcp") != NULL &&
 632                     lxi_iface_dhcp(iface, ficp) != 0) {
 633                         lxi_warn("Failed to start DHCP on %s\n", iface);
 634                 }
 635 
 636                 /*
 637                  * Copy the ipaddrs string, since strtok_r will write NUL
 638                  * characters into it.
 639                  */
 640                 (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
 641                 tmp = ipaddrs_copy;
 642 
 643                 /*
 644                  * Iterate over each IP and then set it up on the interface.
 645                  */
 646                 while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
 647                         tmp = NULL;
 648                         if (strcmp(ipaddr, "addrconf") == 0) {
 649                                 do_addrconf = B_TRUE;
 650                         } else if (strcmp(ipaddr, "dhcp") == 0) {
 651                                 continue;
 652                         } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
 653                                 lxi_warn("Unable to add new IP address (%s) "
 654                                     "to interface %s", ipaddr, iface);
 655                         }
 656                 }
 657 
 658                 if (zone_find_attr(attrs, "primary", &primary) == 0 &&
 659                     strncmp(primary, "true", MAXNAMELEN) == 0 &&
 660                     zone_find_attr(attrs, "gateway", &gateway) == 0) {
 661                         if (lxi_iface_gateway(iface, NULL, 0, gateway) != 0) {
 662                                 lxi_err("default route on %s -> %s failed",
 663                                     iface, gateway);
 664                         }
 665                 }
 666         }
 667 
 668         if (do_addrconf) {
 669                 lxi_net_ndpd_start();
 670         }
 671 
 672         (void) zonecfg_endnwifent(handle);
 673 }
 674 
 675 static void
 676 lxi_net_static_route(const char *line)
 677 {
 678         /*
 679          * Each static route line is a string of the form:
 680          *
 681          *      "10.77.77.2|10.1.1.0/24|false"
 682          *
 683          * i.e. gateway address, destination network, and whether this is
 684          * a "link local" route or a next hop route.
 685          */
 686         custr_t *cu = NULL;


 789 lxi_config_close(zone_dochandle_t handle)
 790 {
 791         zonecfg_fini_handle(handle);
 792 }
 793 
 794 static void
 795 lxi_init_exec(char **argv)
 796 {
 797         const char *cmd = "/sbin/init";
 798         char *const envp[] = { "container=zone", NULL };
 799         int e;
 800 
 801         argv[0] = "init";
 802 
 803         /*
 804          * systemd uses the 'container' env var to determine it is running
 805          * inside a container. It only supports a few well-known types and
 806          * treats anything else as 'other' but this is enough to make it
 807          * behave better inside a zone. See 'detect_container' in systemd.
 808          */
 809         (void) execve(cmd, argv, envp);
 810         e = errno;
 811 
 812         /*
 813          * Because stdout was closed prior to exec, it must be opened again in
 814          * the face of failure to log the error.
 815          */
 816         lxi_log_open();
 817         lxi_err("execve(%s) failed: %s", cmd, strerror(e));
 818 }
 819 
 820 /*ARGSUSED*/
 821 int
 822 main(int argc, char *argv[])
 823 {
 824         zone_dochandle_t handle;
 825 
 826         lxi_log_open();
 827 
 828         lxi_net_ipmgmtd_start();
 829         lxi_net_ipadm_open();