@@ 491,6 491,79 @@ lxi_iface_ipv6_link_local(const char *iface)
}
static int
+lxi_iface_linklocal(const char *dst, int dstpfx, const char *gwaddr)
+{
+ int len, sockfd;
+ char rtbuf[RTMBUFSZ];
+ struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
+ struct sockaddr_in *dst_sin = (struct sockaddr_in *)
+ (rtbuf + sizeof (struct rt_msghdr));
+ struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(dst_sin + 1);
+ struct sockaddr_in *gw_sin = (struct sockaddr_in *)(netmask_sin + 1);
+
+ (void) bzero(rtm, RTMBUFSZ);
+ rtm->rtm_addrs = RTA_IFA | RTA_DST | RTA_NETMASK;
+ rtm->rtm_flags = RTF_UP | RTF_STATIC;
+ if(dstpfx == 32)
+ rtm->rtm_flags |= RTF_HOST;
+ rtm->rtm_msglen = sizeof (rtbuf);
+ rtm->rtm_pid = getpid();
+ rtm->rtm_type = RTM_ADD;
+ rtm->rtm_version = RTM_VERSION;
+
+
+ /*
+ * The destination and netmask components have already been zeroed,
+ * which represents the default gateway. If we were passed a more
+ * specific destination network, use that instead.
+ */
+ dst_sin->sin_family = AF_INET;
+ netmask_sin->sin_family = AF_INET;
+ if (dst != NULL) {
+ struct sockaddr *mask = (struct sockaddr *)netmask_sin;
+
+ if ((inet_pton(AF_INET, dst, &(dst_sin->sin_addr))) != 1 ||
+ plen2mask(dstpfx, AF_INET, mask) != 0) {
+ lxi_warn("bad destination network %s/%d: %s", dst,
+ dstpfx, strerror(errno));
+ return (-1);
+ }
+ }
+
+ if ((inet_pton(AF_INET, gwaddr, &(gw_sin->sin_addr))) != 1) {
+ lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
+ return (-1);
+ }
+
+/* if (iface != NULL) {
+ if ((idx = if_nametoindex(iface)) == 0) {
+ lxi_warn("unable to get interface index for %s: %s\n",
+ iface, strerror(errno));
+ return (-1);
+ }
+ rtm->rtm_index = idx;
+ }*/
+
+ if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+ lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
+ return (-1);
+ }
+
+ if ((len = write(sockfd, rtbuf, rtm->rtm_msglen)) < 0) {
+ lxi_warn("could not write rtmsg: %s", strerror(errno));
+ close(sockfd);
+ return (-1);
+ } else if (len < rtm->rtm_msglen) {
+ lxi_warn("write() rtmsg incomplete");
+ close(sockfd);
+ return (-1);
+ }
+
+ close(sockfd);
+ return (0);
+}
+
+static int
lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
const char *gwaddr)
{
@@ 634,7 707,7 @@ lxi_net_setup(zone_dochandle_t handle)
while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
const char *iface = lookup.zone_nwif_physical;
struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
- const char *ipaddrs, *primary, *gateway;
+ const char *ipaddrs;
char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
*ipaddr, *tmp, *lasts;
boolean_t first_ipv4_configured = B_FALSE;
@@ 684,12 757,6 @@ lxi_net_setup(zone_dochandle_t handle)
"to interface %s", ipaddr, iface);
}
}
-
- if (zone_find_attr(attrs, "primary", &primary) == 0 &&
- strncmp(primary, "true", MAXNAMELEN) == 0 &&
- zone_find_attr(attrs, "gateway", &gateway) == 0) {
- lxi_iface_gateway(iface, NULL, 0, gateway);
- }
}
if (do_addrconf) {
@@ 700,6 767,113 @@ lxi_net_setup(zone_dochandle_t handle)
}
static void
+lxi_net_setup_gateways(zone_dochandle_t handle)
+{
+ struct zone_nwiftab lookup;
+
+ if (zonecfg_setnwifent(handle) != Z_OK)
+ return;
+ while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
+ const char *iface = lookup.zone_nwif_physical;
+ struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
+ const char *primary, *gateway;
+
+ if (zone_find_attr(attrs, "primary", &primary) == 0 &&
+ strncmp(primary, "true", MAXNAMELEN) == 0 &&
+ zone_find_attr(attrs, "gateway", &gateway) == 0) {
+ lxi_iface_gateway(iface, NULL, 0, gateway);
+ }
+ }
+
+ (void) zonecfg_endnwifent(handle);
+}
+
+static void
+lxi_net_linklocal_route(const char *line)
+{
+ /*
+ * Each link-local route line is a string of the form:
+ *
+ * "10.77.77.2|10.1.1.0/24|true"
+ *
+ * i.e. gateway address, destination network, and whether this is
+ * a "link local" route or a next hop route.
+ */
+ custr_t *cu = NULL;
+ char *gw = NULL, *dst = NULL;
+ int pfx = -1;
+ int i;
+
+ if (custr_alloc(&cu) != 0) {
+ lxi_err("custr_alloc failure");
+ }
+
+ for (i = 0; line[i] != '\0'; i++) {
+ if (gw == NULL) {
+ if (line[i] == '|') {
+ if ((gw = strdup(custr_cstr(cu))) == NULL) {
+ lxi_err("strdup failure");
+ }
+ custr_reset(cu);
+ } else {
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+ continue;
+ }
+
+ if (dst == NULL) {
+ if (line[i] == '|') {
+ if ((dst = strdup(custr_cstr(cu))) == NULL) {
+ lxi_err("strdup failure");
+ }
+ custr_reset(cu);
+ } else {
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+ continue;
+ }
+
+ if (pfx == -1) {
+ if (line[i] == '|') {
+ pfx = atoi(custr_cstr(cu));
+ custr_reset(cu);
+ } else {
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+ continue;
+ }
+
+ if (custr_appendc(cu, line[i]) != 0) {
+ lxi_err("custr_appendc failure");
+ }
+ }
+
+ /*
+ * We currently only support link-local routes, so ensure that
+ * "linklocal" is true:
+ */
+ lxi_warn("cu: %s\n", custr_cstr(cu));
+ if (strcmp(custr_cstr(cu), "true") != 0) {
+ lxi_warn("skipping next-hop route: %s", line);
+ } else
+ if (lxi_iface_linklocal(dst, pfx, gw) != 0) {
+ lxi_err("failed to add link local route: %s/%d -> %s", dst, pfx, gw);
+ }
+
+
+ custr_free(cu);
+ free(gw);
+ free(dst);
+}
+
+
+static void
lxi_net_static_route(const char *line)
{
/*
@@ 770,10 944,8 @@ lxi_net_static_route(const char *line)
* "linklocal" is false:
*/
if (strcmp(custr_cstr(cu), "false") != 0) {
- lxi_warn("invalid static route: %s", line);
- }
-
- if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
+ lxi_warn("skipping link-local route: %s", line);
+ } else if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
lxi_err("failed to add route: %s/%d -> %s", dst, pfx, gw);
}
@@ 783,6 955,36 @@ lxi_net_static_route(const char *line)
}
static void
+lxi_net_linklocal_routes(void)
+{
+ const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
+ char *const argv[] = { "routeinfo", NULL };
+ char *const envp[] = { NULL };
+ int code;
+ struct stat st;
+ char errbuf[512];
+
+ if (stat(cmd, &st) != 0 || !S_ISREG(st.st_mode)) {
+ /*
+ * This binary is (potentially) shipped from another
+ * consolidation. If it does not exist, then the platform does
+ * not currently support static routes for LX-branded zones.
+ */
+ return;
+ }
+
+ /*
+ * Run the command, firing the callback for each line that it
+ * outputs. When this function returns, static route processing
+ * is complete.
+ */
+ if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
+ lxi_net_linklocal_route, &code) != 0 || code != 0) {
+ lxi_err("failed to run \"%s\": %s", cmd, errbuf);
+ }
+}
+
+static void
lxi_net_static_routes(void)
{
const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
@@ 917,6 1119,10 @@ main(int argc, char *argv[])
handle = lxi_config_open();
lxi_net_loopback();
lxi_net_setup(handle);
+
+ lxi_net_linklocal_routes();
+ lxi_net_setup_gateways(handle);
+
lxi_config_close(handle);
lxi_net_static_routes();