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 static void
208 lxi_svc_start(char *name, char *path, char *fmri)
209 {
210 pid_t pid;
211 int status;
212 char *argv[] = {
213 NULL,
214 NULL
215 };
216 char *envp[] = {
217 NULL,
218 NULL
219 };
220 argv[0] = name;
221 envp[0] = fmri;
222
223 pid = fork();
224 if (pid == -1) {
225 lxi_err("fork() failed: %s", strerror(errno));
390 goto done;
391 }
392
393 if ((status = ipadm_create_addr(iph, ipaddr,
394 IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
395 lxi_warn("ipadm_create_addr error for %s: %s\n", iface,
396 ipadm_status2str(status));
397 err = -4;
398 goto done;
399 }
400
401 if (af == AF_INET) {
402 *first_ipv4_configured = B_TRUE;
403 }
404
405 done:
406 ipadm_destroy_addrobj(ipaddr);
407 return (err);
408 }
409
410 #if 0 /* XXX KEBE SAYS NOT YET */
411 static int
412 lxi_iface_dhcp(const char *origiface, boolean_t *first_ipv4_configured)
413 {
414 dhcp_ipc_request_t *dhcpreq = NULL;
415 dhcp_ipc_reply_t *dhcpreply = NULL;
416 int err = 0, timeout = 5;
417 char iface[LIFNAMSIZ];
418
419 (void) strncpy(iface, origiface, sizeof (iface));
420
421 if (lxi_getif(AF_INET, iface, sizeof (iface), *first_ipv4_configured)
422 != 0) {
423 lxi_warn("failed to create new logical interface "
424 "on %s: %s", origiface, strerror(errno));
425 return (-1);
426 }
427
428 if (dhcp_start_agent(timeout) != 0) {
429 lxi_err("Failed to start dhcpagent\n");
430 /* NOTREACHED */
442 if (err != 0) {
443 free(dhcpreq);
444 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
445 dhcp_ipc_strerror(err));
446 return (-1);
447 }
448 err = dhcpreply->return_code;
449 if (err != 0) {
450 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
451 dhcp_ipc_strerror(err));
452 goto done;
453 }
454
455 *first_ipv4_configured = B_TRUE;
456
457 done:
458 free(dhcpreq);
459 free(dhcpreply);
460 return (err);
461 }
462 #endif /* XXX KEBE SAYS NOT YET */
463
464 /*
465 * Initialize an IPv6 link-local address on a given interface
466 */
467 static int
468 lxi_iface_ipv6_link_local(const char *iface)
469 {
470 struct lifreq lifr;
471 int s;
472
473 s = socket(AF_INET6, SOCK_DGRAM, 0);
474 if (s == -1) {
475 lxi_warn("socket error %d: bringing up %s: %s",
476 errno, iface, strerror(errno));
477 }
478
479 (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
480 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
481 lxi_warn("SIOCGLIFFLAGS error %d: bringing up %s: %s",
482 errno, iface, strerror(errno));
560 lxi_warn("write() rtmsg incomplete");
561 (void) close(sockfd);
562 return (-1);
563 }
564
565 (void) close(sockfd);
566 return (0);
567 }
568
569 static void
570 lxi_net_loopback()
571 {
572 const char *iface = "lo0";
573 boolean_t first_ipv4_configured = B_FALSE;
574
575 lxi_net_plumb(iface);
576 (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
577 (void) lxi_iface_ipv6_link_local(iface);
578 }
579
580
581
582 #if 0 /* XXX KEBE SAYS NOT YET */
583 /*
584 * This function is used when the "ips" property doesn't exist in a zone's
585 * configuration. It may be an older configuration, so we should search for
586 * "ip" and "netmask" and convert them into the new format.
587 */
588 static int
589 lxi_get_old_ip(struct zone_res_attrtab *attrs, const char **ipaddrs,
590 char *cidraddr, int len)
591 {
592
593 const char *netmask;
594 int prefixlen;
595 struct sockaddr_in mask_sin;
596
597 lxi_warn("Could not find \"ips\" property for zone. Looking "
598 "for older \"ip\" and \"netmask\" properties, instead.");
599
600 if (zone_find_attr(attrs, "ip", ipaddrs) != 0) {
601 return (-1);
602 }
603
604 if (strcmp(*ipaddrs, "dhcp") == 0) {
605 return (0);
606 }
607
608 if (zone_find_attr(attrs, "netmask", &netmask) != 0) {
609 lxi_err("could not find netmask for interface");
610 /* NOTREACHED */
611 }
612
613 /* Convert the netmask to a number */
614 mask_sin.sin_family = AF_INET;
615 if (inet_pton(AF_INET, netmask, &mask_sin.sin_addr) != 1) {
616 lxi_err("invalid netmask address: %s\n",
617 strerror(errno));
618 /* NOTREACHED */
619 }
620 prefixlen = mask2plen((struct sockaddr *)&mask_sin);
621
622 /*
623 * Write out the IP address in the new format and use
624 * that instead
625 */
626 (void) snprintf(cidraddr, len, "%s/%d", *ipaddrs, prefixlen);
627
628 *ipaddrs = cidraddr;
629 return (0);
630 }
631 #endif /* XXX KEBE SAYS NOT YET */
632
633 static void
634 lxi_net_setup(zone_dochandle_t handle)
635 {
636 struct zone_nwiftab lookup;
637 boolean_t do_addrconf = B_FALSE;
638
639 if (zonecfg_setnwifent(handle) != Z_OK)
640 return;
641 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
642 const char *iface = lookup.zone_nwif_physical;
643 #if 0 /* XXX KEBE SAYS NOT YET */
644 struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
645 const char *ipaddrs, *primary, *gateway;
646 char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
647 *ipaddr, *tmp, *lasts;
648 boolean_t first_ipv4_configured = B_FALSE;
649 boolean_t *ficp = &first_ipv4_configured;
650 #endif /* XXX KEBE */
651
652 lxi_net_plumb(iface);
653
654 /* XXX KEBE SAYS this bit was shuffled around. */
655 if (lxi_iface_ipv6_link_local(iface) != 0) {
656 lxi_warn("unable to bring up link-local address on "
657 "interface %s", iface);
658 } else {
659 /* XXX KEBE SAYS this bit is new. */
660 do_addrconf = B_TRUE;
661 }
662
663 #if 0 /* XXX KEBE SAYS NOT YET */
664 if (zone_find_attr(attrs, "ips", &ipaddrs) != 0 &&
665 lxi_get_old_ip(attrs, &ipaddrs, cidraddr, BUFSIZ) != 0) {
666 lxi_warn("Could not find a valid network configuration "
667 "for the %s interface", iface);
668 continue;
669 }
670
671 /*
672 * If we're going to be doing DHCP, we have to do it first since
673 * dhcpagent doesn't like to operate on non-zero logical
674 * interfaces.
675 */
676 if (strstr(ipaddrs, "dhcp") != NULL &&
677 lxi_iface_dhcp(iface, ficp) != 0) {
678 lxi_warn("Failed to start DHCP on %s\n", iface);
679 }
680
681 /*
682 * Copy the ipaddrs string, since strtok_r will write NUL
683 * characters into it.
684 */
685 (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
686 tmp = ipaddrs_copy;
687
688 /*
689 * Iterate over each IP and then set it up on the interface.
690 */
691 while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
692 tmp = NULL;
693 if (strcmp(ipaddr, "addrconf") == 0) {
694 do_addrconf = B_TRUE;
695 } else if (strcmp(ipaddr, "dhcp") == 0) {
696 continue;
697 } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
698 lxi_warn("Unable to add new IP address (%s) "
699 "to interface %s", ipaddr, iface);
700 }
701 }
702
703 if (zone_find_attr(attrs, "primary", &primary) == 0 &&
704 strncmp(primary, "true", MAXNAMELEN) == 0 &&
705 zone_find_attr(attrs, "gateway", &gateway) == 0) {
706 lxi_iface_gateway(iface, NULL, 0, gateway);
707 }
708 #endif /* XXX KEBE */
709 }
710
711 if (do_addrconf) {
712 lxi_net_ndpd_start();
713 }
714
715 (void) zonecfg_endnwifent(handle);
716 }
717
718 static void
719 lxi_net_static_route(const char *line)
720 {
721 /*
722 * Each static route line is a string of the form:
723 *
724 * "10.77.77.2|10.1.1.0/24|false"
725 *
726 * i.e. gateway address, destination network, and whether this is
727 * a "link local" route or a next hop route.
728 */
|
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 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));
388 goto done;
389 }
390
391 if ((status = ipadm_create_addr(iph, ipaddr,
392 IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
393 lxi_warn("ipadm_create_addr error for %s: %s\n", iface,
394 ipadm_status2str(status));
395 err = -4;
396 goto done;
397 }
398
399 if (af == AF_INET) {
400 *first_ipv4_configured = B_TRUE;
401 }
402
403 done:
404 ipadm_destroy_addrobj(ipaddr);
405 return (err);
406 }
407
408 static int
409 lxi_iface_dhcp(const char *origiface, boolean_t *first_ipv4_configured)
410 {
411 dhcp_ipc_request_t *dhcpreq = NULL;
412 dhcp_ipc_reply_t *dhcpreply = NULL;
413 int err = 0, timeout = 5;
414 char iface[LIFNAMSIZ];
415
416 (void) strncpy(iface, origiface, sizeof (iface));
417
418 if (lxi_getif(AF_INET, iface, sizeof (iface), *first_ipv4_configured)
419 != 0) {
420 lxi_warn("failed to create new logical interface "
421 "on %s: %s", origiface, strerror(errno));
422 return (-1);
423 }
424
425 if (dhcp_start_agent(timeout) != 0) {
426 lxi_err("Failed to start dhcpagent\n");
427 /* NOTREACHED */
439 if (err != 0) {
440 free(dhcpreq);
441 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
442 dhcp_ipc_strerror(err));
443 return (-1);
444 }
445 err = dhcpreply->return_code;
446 if (err != 0) {
447 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
448 dhcp_ipc_strerror(err));
449 goto done;
450 }
451
452 *first_ipv4_configured = B_TRUE;
453
454 done:
455 free(dhcpreq);
456 free(dhcpreply);
457 return (err);
458 }
459
460 /*
461 * Initialize an IPv6 link-local address on a given interface
462 */
463 static int
464 lxi_iface_ipv6_link_local(const char *iface)
465 {
466 struct lifreq lifr;
467 int s;
468
469 s = socket(AF_INET6, SOCK_DGRAM, 0);
470 if (s == -1) {
471 lxi_warn("socket error %d: bringing up %s: %s",
472 errno, iface, strerror(errno));
473 }
474
475 (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
476 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
477 lxi_warn("SIOCGLIFFLAGS error %d: bringing up %s: %s",
478 errno, iface, strerror(errno));
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.
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 lxi_iface_gateway(iface, NULL, 0, gateway);
662 }
663 }
664
665 if (do_addrconf) {
666 lxi_net_ndpd_start();
667 }
668
669 (void) zonecfg_endnwifent(handle);
670 }
671
672 static void
673 lxi_net_static_route(const char *line)
674 {
675 /*
676 * Each static route line is a string of the form:
677 *
678 * "10.77.77.2|10.1.1.0/24|false"
679 *
680 * i.e. gateway address, destination network, and whether this is
681 * a "link local" route or a next hop route.
682 */
|