Print this page
want lxinit to support link-local routes
| 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 2018 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 <libcustr.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 #define HOOK_POSTNET_PATH "/usr/lib/brand/lx/lx_hook_postnet"
78 78
79 79 #define PREFIX_LOG_WARN "lx_init warn: "
80 80 #define PREFIX_LOG_ERR "lx_init err: "
81 81
82 82 #define RTMBUFSZ (sizeof (struct rt_msghdr) + \
83 83 (3 * sizeof (struct sockaddr_in)))
84 84
85 85 ipadm_handle_t iph;
86 86
87 87 static void
88 88 lxi_err(char *msg, ...)
89 89 {
90 90 char buf[1024];
91 91 int len;
92 92 va_list ap;
93 93
94 94 va_start(ap, msg);
95 95 /*LINTED*/
96 96 len = vsnprintf(buf, sizeof (buf), msg, ap);
97 97 va_end(ap);
98 98
99 99 (void) write(1, PREFIX_LOG_ERR, strlen(PREFIX_LOG_ERR));
100 100 (void) write(1, buf, len);
101 101 (void) write(1, "\n", 1);
102 102
103 103 /*
104 104 * Since a non-zero exit will cause the zone to reboot, a pause here
105 105 * will prevent a mis-configured zone from spinning in a reboot loop.
106 106 */
107 107 pause();
108 108 exit(1);
109 109 /*NOTREACHED*/
110 110 }
111 111
112 112 static void
113 113 lxi_warn(char *msg, ...)
114 114 {
115 115 char buf[1024];
116 116 int len;
117 117 va_list ap;
118 118
119 119 va_start(ap, msg);
120 120 /*LINTED*/
121 121 len = vsnprintf(buf, sizeof (buf), msg, ap);
122 122 va_end(ap);
123 123
124 124 (void) write(1, PREFIX_LOG_WARN, strlen(PREFIX_LOG_WARN));
125 125 (void) write(1, buf, len);
126 126 (void) write(1, "\n", 1);
127 127 }
128 128
129 129 static void
130 130 lxi_log_open()
131 131 {
132 132 int fd = open("/dev/console", O_WRONLY);
133 133
134 134 if (fd < 0) {
135 135 /* hard to log at this point... */
136 136 exit(1);
137 137 } else if (fd != 1) {
138 138 /*
139 139 * Use stdout as the log fd. Init should start with no files
140 140 * open, so we should be required to perform this relocation
141 141 * every time.
142 142 */
143 143 if (dup2(fd, 1) != 1) {
144 144 exit(1);
145 145 }
146 146 }
147 147 }
148 148
149 149 static void
150 150 lxi_log_close()
151 151 {
152 152 (void) close(0);
153 153 (void) close(1);
154 154 }
155 155
156 156 static zone_dochandle_t
157 157 lxi_config_open()
158 158 {
159 159 zoneid_t zoneid;
160 160 char zonename[ZONENAME_MAX];
161 161 zone_dochandle_t handle;
162 162 zone_iptype_t iptype;
163 163 int res;
164 164
165 165 zoneid = getzoneid();
166 166 if (getzonenamebyid(zoneid, zonename, sizeof (zonename)) < 0) {
167 167 lxi_err("could not determine zone name");
168 168 }
169 169
170 170 if ((handle = zonecfg_init_handle()) == NULL)
171 171 lxi_err("internal libzonecfg.so.1 error", 0);
172 172
173 173 if ((res = zonecfg_get_handle(zonename, handle)) != Z_OK) {
174 174 zonecfg_fini_handle(handle);
175 175 lxi_err("could not locate zone config %d", res);
176 176 }
177 177
178 178 /*
179 179 * Only exclusive stack is supported.
180 180 */
181 181 if (zonecfg_get_iptype(handle, &iptype) != Z_OK ||
182 182 iptype != ZS_EXCLUSIVE) {
183 183 zonecfg_fini_handle(handle);
184 184 lxi_err("lx zones do not support shared IP stacks");
185 185 }
186 186
187 187 return (handle);
188 188
189 189 }
190 190
191 191 static int
192 192 zone_find_attr(struct zone_res_attrtab *attrs, const char *name,
193 193 const char **result)
194 194 {
195 195 while (attrs != NULL) {
196 196 if (strncmp(attrs->zone_res_attr_name, name,
197 197 MAXNAMELEN) == 0) {
198 198 *result = attrs->zone_res_attr_value;
199 199 return (0);
200 200 }
201 201 attrs = attrs->zone_res_attr_next;
202 202 }
203 203 return (-1);
204 204 }
205 205
206 206 void
207 207 lxi_svc_start(char *name, char *path, char *fmri)
208 208 {
209 209 pid_t pid;
210 210 int status;
211 211 char *const argv[] = {
212 212 name,
213 213 NULL
214 214 };
215 215 char *const envp[] = {
216 216 fmri,
217 217 NULL
218 218 };
219 219
220 220 pid = fork();
221 221 if (pid == -1) {
222 222 lxi_err("fork() failed: %s", strerror(errno));
223 223 }
224 224
225 225 if (pid == 0) {
226 226 /* child */
227 227 const char *zroot = zone_get_nroot();
228 228 char cmd[MAXPATHLEN];
229 229
230 230 /*
231 231 * Construct the full path to the binary, including the native
232 232 * system root (e.g. "/native") if in use for this zone:
233 233 */
234 234 (void) snprintf(cmd, sizeof (cmd), "%s%s", zroot != NULL ?
235 235 zroot : "", path);
236 236
237 237 execve(cmd, argv, envp);
238 238
239 239 lxi_err("execve(%s) failed: %s", cmd, strerror(errno));
240 240 /* NOTREACHED */
241 241 }
242 242
243 243 /* parent */
244 244 while (wait(&status) != pid) {
245 245 /* EMPTY */;
246 246 }
247 247
248 248 if (WIFEXITED(status)) {
249 249 if (WEXITSTATUS(status) != 0) {
250 250 lxi_err("%s[%d] exited: %d", name,
251 251 (int)pid, WEXITSTATUS(status));
252 252 }
253 253 } else if (WIFSIGNALED(status)) {
254 254 lxi_err("%s[%d] died on signal: %d", name,
255 255 (int)pid, WTERMSIG(status));
256 256 } else {
257 257 lxi_err("%s[%d] failed in unknown way", name,
258 258 (int)pid);
259 259 }
260 260 }
261 261
262 262 void
263 263 lxi_net_ipmgmtd_start()
264 264 {
265 265 lxi_svc_start("ipmgmtd", IPMGMTD_PATH,
266 266 "SMF_FMRI=svc:/network/ip-interface-management:default");
267 267 }
268 268
269 269 void
270 270 lxi_net_ndpd_start()
271 271 {
272 272 lxi_svc_start("in.ndpd", IN_NDPD_PATH,
273 273 "SMF_FMRI=svc:/network/routing/ndp:default");
274 274 }
275 275
276 276
277 277 static void
278 278 lxi_net_ipadm_open()
279 279 {
280 280 ipadm_status_t status;
281 281
282 282 if ((status = ipadm_open(&iph, IPH_LEGACY)) != IPADM_SUCCESS) {
283 283 lxi_err("Error opening ipadm handle: %s",
284 284 ipadm_status2str(status));
285 285 }
286 286 }
287 287
288 288 static void
289 289 lxi_net_ipadm_close()
290 290 {
291 291 ipadm_close(iph);
292 292 }
293 293
294 294 void
295 295 lxi_net_plumb(const char *iface)
296 296 {
297 297 ipadm_status_t status;
298 298 char ifbuf[LIFNAMSIZ];
299 299
300 300 /* ipadm_create_if stomps on ifbuf, so create a copy: */
301 301 (void) strncpy(ifbuf, iface, sizeof (ifbuf));
302 302
303 303 if ((status = ipadm_create_if(iph, ifbuf, AF_INET, IPADM_OPT_ACTIVE))
304 304 != IPADM_SUCCESS) {
305 305 lxi_err("ipadm_create_if error %d: %s/v4: %s",
306 306 status, iface, ipadm_status2str(status));
307 307 }
308 308
309 309 if ((status = ipadm_create_if(iph, ifbuf, AF_INET6, IPADM_OPT_ACTIVE))
310 310 != IPADM_SUCCESS) {
311 311 lxi_err("ipadm_create_if error %d: %s/v6: %s",
312 312 status, iface, ipadm_status2str(status));
313 313 }
314 314 }
315 315
316 316 static int
317 317 lxi_getif(int af, char *iface, int len, boolean_t first_ipv4_configured)
318 318 {
319 319 struct lifreq lifr;
320 320 int s = socket(af, SOCK_DGRAM, 0);
321 321 if (s < 0) {
322 322 lxi_warn("socket error %d: bringing up %s: %s",
323 323 errno, iface, strerror(errno));
324 324 return (-1);
325 325 }
326 326
327 327 /*
328 328 * We need a new logical interface for every IP address we add, except
329 329 * for the very first IPv4 address.
330 330 */
331 331 if (af == AF_INET6 || first_ipv4_configured) {
332 332 (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
333 333 (void) memset(&lifr.lifr_addr, 0, sizeof (lifr.lifr_addr));
334 334 if (ioctl(s, SIOCLIFADDIF, (caddr_t)&lifr) < 0) {
335 335 if (close(s) != 0) {
336 336 lxi_warn("failed to close socket: %s\n",
337 337 strerror(errno));
338 338 }
339 339 return (-1);
340 340 }
341 341 (void) strncpy(iface, lifr.lifr_name, len);
342 342 }
343 343
344 344 if (close(s) != 0) {
345 345 lxi_warn("failed to close socket: %s\n",
346 346 strerror(errno));
347 347 }
348 348 return (0);
349 349 }
350 350
351 351 static int
352 352 lxi_iface_ip(const char *origiface, const char *addr,
353 353 boolean_t *first_ipv4_configured)
354 354 {
355 355 static int addrnum = 0;
356 356 ipadm_status_t status;
357 357 ipadm_addrobj_t ipaddr = NULL;
358 358 char iface[LIFNAMSIZ];
359 359 char aobjname[IPADM_AOBJSIZ];
360 360 int af, err = 0;
361 361
362 362 (void) strncpy(iface, origiface, sizeof (iface));
363 363
364 364 af = strstr(addr, ":") == NULL ? AF_INET : AF_INET6;
365 365 if (lxi_getif(af, iface, sizeof (iface), *first_ipv4_configured) != 0) {
366 366 lxi_warn("failed to create new logical interface "
367 367 "on %s: %s", origiface, strerror(errno));
368 368 return (-1);
369 369 }
370 370
371 371 (void) snprintf(aobjname, IPADM_AOBJSIZ, "%s/addr%d", iface,
372 372 addrnum++);
373 373
374 374 if ((status = ipadm_create_addrobj(IPADM_ADDR_STATIC, aobjname,
375 375 &ipaddr)) != IPADM_SUCCESS) {
376 376 lxi_warn("ipadm_create_addrobj error %d: addr %s, "
377 377 "interface %s: %s\n", status, addr, iface,
378 378 ipadm_status2str(status));
379 379 return (-2);
380 380 }
381 381
382 382 if ((status = ipadm_set_addr(ipaddr, addr, AF_UNSPEC))
383 383 != IPADM_SUCCESS) {
384 384 lxi_warn("ipadm_set_addr error %d: addr %s"
385 385 ", interface %s: %s\n", status, addr,
386 386 iface, ipadm_status2str(status));
387 387 err = -3;
388 388 goto done;
389 389 }
390 390
391 391 if ((status = ipadm_create_addr(iph, ipaddr,
392 392 IPADM_OPT_ACTIVE | IPADM_OPT_UP)) != IPADM_SUCCESS) {
393 393 lxi_warn("ipadm_create_addr error for %s: %s\n", iface,
394 394 ipadm_status2str(status));
395 395 err = -4;
396 396 goto done;
397 397 }
398 398
399 399 if (af == AF_INET) {
400 400 *first_ipv4_configured = B_TRUE;
401 401 }
402 402
403 403 done:
404 404 ipadm_destroy_addrobj(ipaddr);
405 405 return (err);
406 406 }
407 407
408 408 static int
409 409 lxi_iface_dhcp(const char *origiface, boolean_t *first_ipv4_configured)
410 410 {
411 411 dhcp_ipc_request_t *dhcpreq = NULL;
412 412 dhcp_ipc_reply_t *dhcpreply = NULL;
413 413 int err = 0, timeout = 5;
414 414 char iface[LIFNAMSIZ];
415 415
416 416 (void) strncpy(iface, origiface, sizeof (iface));
417 417
418 418 if (lxi_getif(AF_INET, iface, sizeof (iface), *first_ipv4_configured)
419 419 != 0) {
420 420 lxi_warn("failed to create new logical interface "
421 421 "on %s: %s", origiface, strerror(errno));
422 422 return (-1);
423 423 }
424 424
425 425 if (dhcp_start_agent(timeout) != 0) {
426 426 lxi_err("Failed to start dhcpagent\n");
427 427 /* NOTREACHED */
428 428 }
429 429
430 430 dhcpreq = dhcp_ipc_alloc_request(DHCP_START, iface,
431 431 NULL, 0, DHCP_TYPE_NONE);
432 432 if (dhcpreq == NULL) {
433 433 lxi_warn("Unable to allocate memory "
434 434 "to start DHCP on %s\n", iface);
435 435 return (-1);
436 436 }
437 437
438 438 err = dhcp_ipc_make_request(dhcpreq, &dhcpreply, timeout);
439 439 if (err != 0) {
440 440 free(dhcpreq);
441 441 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
442 442 dhcp_ipc_strerror(err));
443 443 return (-1);
444 444 }
445 445 err = dhcpreply->return_code;
446 446 if (err != 0) {
447 447 lxi_warn("Failed to start DHCP on %s: %s\n", iface,
448 448 dhcp_ipc_strerror(err));
449 449 goto done;
450 450 }
451 451
452 452 *first_ipv4_configured = B_TRUE;
453 453
454 454 done:
455 455 free(dhcpreq);
456 456 free(dhcpreply);
457 457 return (err);
458 458 }
459 459
460 460 /*
461 461 * Initialize an IPv6 link-local address on a given interface
462 462 */
463 463 static int
464 464 lxi_iface_ipv6_link_local(const char *iface)
465 465 {
466 466 struct lifreq lifr;
467 467 int s;
468 468
469 469 s = socket(AF_INET6, SOCK_DGRAM, 0);
470 470 if (s == -1) {
471 471 lxi_warn("socket error %d: bringing up %s: %s",
472 472 errno, iface, strerror(errno));
473 473 }
474 474
475 475 (void) strncpy(lifr.lifr_name, iface, sizeof (lifr.lifr_name));
476 476 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
477 477 lxi_warn("SIOCGLIFFLAGS error %d: bringing up %s: %s",
478 478 errno, iface, strerror(errno));
479 479 return (-1);
480 480 }
481 481
482 482 lifr.lifr_flags |= IFF_UP;
|
↓ open down ↓ |
482 lines elided |
↑ open up ↑ |
483 483 if (ioctl(s, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
484 484 lxi_warn("SIOCSLIFFLAGS error %d: bringing up %s: %s",
485 485 errno, iface, strerror(errno));
486 486 return (-1);
487 487 }
488 488
489 489 (void) close(s);
490 490 return (0);
491 491 }
492 492
493 +static int lxi_route_send_msg(struct rt_msghdr * rtm)
494 +{
495 + int sockfd, len;
496 +
497 + if ((sockfd = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
498 + lxi_warn("socket(PF_ROUTE): %s\n", strerror(errno));
499 + return (-1);
500 + }
501 +
502 + if ((len = write(sockfd, (const void *)rtm, rtm->rtm_msglen)) < 0) {
503 + lxi_warn("could not write rtmsg: %s", strerror(errno));
504 + close(sockfd);
505 + return (-1);
506 + } else if (len < rtm->rtm_msglen) {
507 + lxi_warn("write() rtmsg incomplete");
508 + close(sockfd);
509 + return (-1);
510 + }
511 +
512 + close(sockfd);
513 + return (0);
514 +}
515 +
493 516 static int
494 517 lxi_iface_gateway(const char *iface, const char *dst, int dstpfx,
495 - const char *gwaddr)
518 + const char *gwaddr, int llroute)
496 519 {
497 - int idx, len, sockfd;
520 + int idx;
498 521 char rtbuf[RTMBUFSZ];
499 522 struct rt_msghdr *rtm = (struct rt_msghdr *)rtbuf;
500 523 struct sockaddr_in *dst_sin = (struct sockaddr_in *)
501 524 (rtbuf + sizeof (struct rt_msghdr));
502 525 struct sockaddr_in *gw_sin = (struct sockaddr_in *)(dst_sin + 1);
503 526 struct sockaddr_in *netmask_sin = (struct sockaddr_in *)(gw_sin + 1);
504 527
505 528 (void) bzero(rtm, RTMBUFSZ);
506 529 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);
530 +
531 + if(!llroute)
532 + rtm->rtm_flags = RTF_UP | RTF_STATIC | RTF_GATEWAY;
533 +
534 + rtm->rtm_msglen = sizeof (rtbuf);
509 535 rtm->rtm_pid = getpid();
510 536 rtm->rtm_type = RTM_ADD;
511 537 rtm->rtm_version = RTM_VERSION;
512 538
513 539
514 540 /*
515 541 * The destination and netmask components have already been zeroed,
516 542 * which represents the default gateway. If we were passed a more
517 543 * specific destination network, use that instead.
518 544 */
545 +
546 + if(dstpfx == -1) {
547 + /*
548 + * no prefix was specified; assume a prefix length of 32,
549 + * which seems in line with the behavior of vmadm.
550 + */
551 + dstpfx = 32;
552 + }
553 +
519 554 dst_sin->sin_family = AF_INET;
520 555 netmask_sin->sin_family = AF_INET;
521 556 if (dst != NULL) {
522 557 struct sockaddr *mask = (struct sockaddr *)netmask_sin;
523 558
524 559 if ((inet_pton(AF_INET, dst, &(dst_sin->sin_addr))) != 1 ||
525 560 plen2mask(dstpfx, AF_INET, mask) != 0) {
526 561 lxi_warn("bad destination network %s/%d: %s", dst,
527 562 dstpfx, strerror(errno));
528 563 return (-1);
529 564 }
530 565 }
531 566
532 567 if ((inet_pton(AF_INET, gwaddr, &(gw_sin->sin_addr))) != 1) {
533 568 lxi_warn("bad gateway %s: %s", gwaddr, strerror(errno));
534 569 return (-1);
535 570 }
|
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
536 571
537 572 if (iface != NULL) {
538 573 if ((idx = if_nametoindex(iface)) == 0) {
539 574 lxi_warn("unable to get interface index for %s: %s\n",
540 575 iface, strerror(errno));
541 576 return (-1);
542 577 }
543 578 rtm->rtm_index = idx;
544 579 }
545 580
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 - close(sockfd);
554 - return (-1);
555 - } else if (len < rtm->rtm_msglen) {
556 - lxi_warn("write() rtmsg incomplete");
557 - close(sockfd);
558 - return (-1);
559 - }
560 -
561 - close(sockfd);
562 - return (0);
581 + return lxi_route_send_msg(rtm);
563 582 }
564 583
565 584 static void
566 585 lxi_net_loopback()
567 586 {
568 587 const char *iface = "lo0";
569 588 boolean_t first_ipv4_configured = B_FALSE;
570 589
571 590 lxi_net_plumb(iface);
572 591 (void) lxi_iface_ip(iface, "127.0.0.1/8", &first_ipv4_configured);
573 592 (void) lxi_iface_ipv6_link_local(iface);
574 593 }
575 594
576 595
577 596 /*
578 597 * This function is used when the "ips" property doesn't exist in a zone's
579 598 * configuration. It may be an older configuration, so we should search for
580 599 * "ip" and "netmask" and convert them into the new format.
581 600 */
582 601 static int
583 602 lxi_get_old_ip(struct zone_res_attrtab *attrs, const char **ipaddrs,
584 603 char *cidraddr, int len)
585 604 {
586 605
587 606 const char *netmask;
588 607 int prefixlen;
589 608 struct sockaddr_in mask_sin;
590 609
591 610 lxi_warn("Could not find \"ips\" property for zone. Looking "
592 611 "for older \"ip\" and \"netmask\" properties, instead.");
593 612
594 613 if (zone_find_attr(attrs, "ip", ipaddrs) != 0) {
595 614 return (-1);
596 615 }
597 616
598 617 if (strcmp(*ipaddrs, "dhcp") == 0) {
599 618 return (0);
600 619 }
601 620
602 621 if (zone_find_attr(attrs, "netmask", &netmask) != 0) {
603 622 lxi_err("could not find netmask for interface");
604 623 /* NOTREACHED */
605 624 }
606 625
607 626 /* Convert the netmask to a number */
608 627 mask_sin.sin_family = AF_INET;
609 628 if (inet_pton(AF_INET, netmask, &mask_sin.sin_addr) != 1) {
610 629 lxi_err("invalid netmask address: %s\n",
611 630 strerror(errno));
612 631 /* NOTREACHED */
613 632 }
614 633 prefixlen = mask2plen((struct sockaddr *)&mask_sin);
615 634
616 635 /*
617 636 * Write out the IP address in the new format and use
618 637 * that instead
619 638 */
620 639 (void) snprintf(cidraddr, len, "%s/%d", *ipaddrs, prefixlen);
621 640
622 641 *ipaddrs = cidraddr;
623 642 return (0);
624 643 }
625 644
626 645 static void
|
↓ open down ↓ |
54 lines elided |
↑ open up ↑ |
627 646 lxi_net_setup(zone_dochandle_t handle)
628 647 {
629 648 struct zone_nwiftab lookup;
630 649 boolean_t do_addrconf = B_FALSE;
631 650
632 651 if (zonecfg_setnwifent(handle) != Z_OK)
633 652 return;
634 653 while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
635 654 const char *iface = lookup.zone_nwif_physical;
636 655 struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
637 - const char *ipaddrs, *primary, *gateway;
656 + const char *ipaddrs;
638 657 char ipaddrs_copy[MAXNAMELEN], cidraddr[BUFSIZ],
639 658 *ipaddr, *tmp, *lasts;
640 659 boolean_t first_ipv4_configured = B_FALSE;
641 660 boolean_t *ficp = &first_ipv4_configured;
642 661
643 662 lxi_net_plumb(iface);
644 663 if (zone_find_attr(attrs, "ips", &ipaddrs) != 0 &&
645 664 lxi_get_old_ip(attrs, &ipaddrs, cidraddr, BUFSIZ) != 0) {
646 665 lxi_warn("Could not find a valid network configuration "
647 666 "for the %s interface", iface);
648 667 continue;
649 668 }
650 669
651 670 if (lxi_iface_ipv6_link_local(iface) != 0) {
652 671 lxi_warn("unable to bring up link-local address on "
653 672 "interface %s", iface);
654 673 }
655 674
656 675 /*
657 676 * If we're going to be doing DHCP, we have to do it first since
658 677 * dhcpagent doesn't like to operate on non-zero logical
659 678 * interfaces.
660 679 */
661 680 if (strstr(ipaddrs, "dhcp") != NULL &&
662 681 lxi_iface_dhcp(iface, ficp) != 0) {
663 682 lxi_warn("Failed to start DHCP on %s\n", iface);
664 683 }
665 684
666 685 /*
667 686 * Copy the ipaddrs string, since strtok_r will write NUL
668 687 * characters into it.
669 688 */
670 689 (void) strlcpy(ipaddrs_copy, ipaddrs, MAXNAMELEN);
671 690 tmp = ipaddrs_copy;
672 691
673 692 /*
674 693 * Iterate over each IP and then set it up on the interface.
675 694 */
676 695 while ((ipaddr = strtok_r(tmp, ",", &lasts)) != NULL) {
|
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
677 696 tmp = NULL;
678 697 if (strcmp(ipaddr, "addrconf") == 0) {
679 698 do_addrconf = B_TRUE;
680 699 } else if (strcmp(ipaddr, "dhcp") == 0) {
681 700 continue;
682 701 } else if (lxi_iface_ip(iface, ipaddr, ficp) < 0) {
683 702 lxi_warn("Unable to add new IP address (%s) "
684 703 "to interface %s", ipaddr, iface);
685 704 }
686 705 }
687 -
688 - if (zone_find_attr(attrs, "primary", &primary) == 0 &&
689 - strncmp(primary, "true", MAXNAMELEN) == 0 &&
690 - zone_find_attr(attrs, "gateway", &gateway) == 0) {
691 - lxi_iface_gateway(iface, NULL, 0, gateway);
692 - }
693 706 }
694 707
695 708 if (do_addrconf) {
696 709 lxi_net_ndpd_start();
697 710 }
698 711
699 712 (void) zonecfg_endnwifent(handle);
700 713 }
701 714
702 715 static void
703 -lxi_net_static_route(const char *line)
716 +lxi_net_setup_gateways(zone_dochandle_t handle)
704 717 {
718 + struct zone_nwiftab lookup;
719 +
720 + if (zonecfg_setnwifent(handle) != Z_OK)
721 + return;
722 + while (zonecfg_getnwifent(handle, &lookup) == Z_OK) {
723 + const char *iface = lookup.zone_nwif_physical;
724 + struct zone_res_attrtab *attrs = lookup.zone_nwif_attrp;
725 + const char *primary, *gateway;
726 +
727 + if (zone_find_attr(attrs, "primary", &primary) == 0 &&
728 + strncmp(primary, "true", MAXNAMELEN) == 0 &&
729 + zone_find_attr(attrs, "gateway", &gateway) == 0) {
730 + lxi_iface_gateway(iface, NULL, 0, gateway, 0);
731 + }
732 + }
733 +
734 + (void) zonecfg_endnwifent(handle);
735 +}
736 +
737 +static void
738 +lxi_parse_route_line(const char *line, custr_t *cu, char *gw, char *dst, int* pfx, int gwlen, int dstlen)
739 +{
740 + int i;
741 + int havegw = 0, havedst = 0, nopfx = 0;
742 +
743 + for (i = 0; line[i] != '\0'; i++) {
744 + if (!havegw) {
745 + if (line[i] == '|') {
746 + if ((strlcpy(gw, custr_cstr(cu), gwlen) ) == 0) {
747 + lxi_err("strlcpy failure");
748 + } else {
749 + havegw = 1;
750 + }
751 + custr_reset(cu);
752 + } else {
753 + if (custr_appendc(cu, line[i]) != 0) {
754 + lxi_err("custr_appendc failure");
755 + }
756 + }
757 + continue;
758 + }
759 +
760 + if (!havedst) {
761 + if (line[i] == '/' || line[i] == '|') {
762 + if ((strlcpy(dst, custr_cstr(cu), dstlen)) == 0) {
763 + lxi_err("strlcpy failure");
764 + } else {
765 + havedst = 1;
766 + if(line[i] == '|') {
767 + nopfx = 1;
768 + }
769 + }
770 + custr_reset(cu);
771 + } else {
772 + if (custr_appendc(cu, line[i]) != 0) {
773 + lxi_err("custr_appendc failure");
774 + }
775 + }
776 + continue;
777 + }
778 +
779 + if (*pfx == -1 && !nopfx) {
780 + if (line[i] == '|') {
781 + *pfx = atoi(custr_cstr(cu));
782 + custr_reset(cu);
783 + } else {
784 + if (custr_appendc(cu, line[i]) != 0) {
785 + lxi_err("custr_appendc failure");
786 + }
787 + }
788 + continue;
789 + }
790 +
791 + if (custr_appendc(cu, line[i]) != 0) {
792 + lxi_err("custr_appendc failure");
793 + }
794 + }
795 +
796 + return;
797 +}
798 +
799 +static void
800 +lxi_net_process_route_line(const char *line, int llonly)
801 +{
705 802 /*
706 803 * Each static route line is a string of the form:
707 804 *
708 805 * "10.77.77.2|10.1.1.0/24|false"
709 806 *
710 807 * i.e. gateway address, destination network, and whether this is
711 808 * a "link local" route or a next hop route.
809 + *
810 + * passing a true value to the llonly argument to this method causes only
811 + * those lines with the link-local flag to be processed and vice-versa
712 812 */
713 813 custr_t *cu = NULL;
714 - char *gw = NULL, *dst = NULL;
715 814 int pfx = -1;
716 - int i;
815 + char gw[INET6_ADDRSTRLEN];
816 + char dst[INET6_ADDRSTRLEN];
717 817
718 818 if (custr_alloc(&cu) != 0) {
719 819 lxi_err("custr_alloc failure");
720 820 }
721 821
722 - for (i = 0; line[i] != '\0'; i++) {
723 - if (gw == NULL) {
724 - if (line[i] == '|') {
725 - if ((gw = strdup(custr_cstr(cu))) == NULL) {
726 - lxi_err("strdup failure");
727 - }
728 - custr_reset(cu);
729 - } else {
730 - if (custr_appendc(cu, line[i]) != 0) {
731 - lxi_err("custr_appendc failure");
732 - }
733 - }
734 - continue;
735 - }
822 + lxi_parse_route_line(line, cu, gw, dst, &pfx, sizeof(gw), sizeof(dst));
736 823
737 - if (dst == NULL) {
738 - if (line[i] == '/') {
739 - if ((dst = strdup(custr_cstr(cu))) == NULL) {
740 - lxi_err("strdup failure");
741 - }
742 - custr_reset(cu);
743 - } else {
744 - if (custr_appendc(cu, line[i]) != 0) {
745 - lxi_err("custr_appendc failure");
746 - }
747 - }
748 - continue;
749 - }
824 + if (llonly && strcmp(custr_cstr(cu), "true") == 0) {
825 + if (lxi_iface_gateway(NULL, dst, pfx, gw, 1) != 0) {
826 + lxi_err("failed to add link-local route: %s/%d -> %s", dst, pfx, gw);
827 + }
828 + } else if(!llonly && strcmp(custr_cstr(cu), "false") == 0) {
829 + if (lxi_iface_gateway(NULL, dst, pfx, gw, 0) != 0) {
830 + lxi_err("failed to add next-hop route: %s/%d -> %s", dst, pfx, gw);
831 + }
832 + } else if(strcmp(custr_cstr(cu), "true") != 0 && strcmp(custr_cstr(cu), "false") != 0) {
833 + /*
834 + * try to be helpful when we encounter something we don't expect.
835 + */
836 + lxi_warn("skipping unknown static route defined in line %s, parsed link-local flag=%s", line, custr_cstr(cu));
837 + }
750 838
751 - if (pfx == -1) {
752 - if (line[i] == '|') {
753 - pfx = atoi(custr_cstr(cu));
754 - custr_reset(cu);
755 - } else {
756 - if (custr_appendc(cu, line[i]) != 0) {
757 - lxi_err("custr_appendc failure");
758 - }
759 - }
760 - continue;
761 - }
839 + custr_free(cu);
840 +}
762 841
763 - if (custr_appendc(cu, line[i]) != 0) {
764 - lxi_err("custr_appendc failure");
765 - }
766 - }
842 +static void
843 +lxi_net_static_route(const char * line) {
844 + /*
845 + * process only those lines where the link-local field is false.
846 + */
847 + lxi_net_process_route_line(line, 0);
848 +}
767 849
850 +static void
851 +lxi_net_linklocal_route(const char * line) {
768 852 /*
769 - * We currently only support "next hop" routes, so ensure that
770 - * "linklocal" is false:
771 - */
772 - if (strcmp(custr_cstr(cu), "false") != 0) {
773 - lxi_warn("invalid static route: %s", line);
774 - }
853 + * processes only those lines where the link-local field is true.
854 + */
855 + lxi_net_process_route_line(line, 1);
856 +}
775 857
776 - if (lxi_iface_gateway(NULL, dst, pfx, gw) != 0) {
777 - lxi_err("failed to add route: %s/%d -> %s", dst, pfx, gw);
778 - }
858 +static void
859 +lxi_run_routeinfo(void * callback)
860 +{
861 + const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
862 + char *const argv[] = { "routeinfo", NULL };
863 + char *const envp[] = { NULL };
864 + int code;
865 + struct stat st;
866 + char errbuf[512];
867 +
868 + if (stat(cmd, &st) != 0 || !S_ISREG(st.st_mode)) {
869 + /*
870 + * This binary is (potentially) shipped from another
871 + * consolidation. If it does not exist, then the platform does
872 + * not currently support link-local or static routes for LX-branded zones.
873 + */
874 + return;
875 + }
779 876
780 - custr_free(cu);
781 - free(gw);
782 - free(dst);
877 + /*
878 + * Run the command, firing the callback for each line that it
879 + * outputs. When this function returns, static route processing
880 + * is complete.
881 + */
882 + if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
883 + callback, &code) != 0 || code != 0) {
884 + lxi_err("failed to run \"%s\": %s", cmd, errbuf);
885 + }
783 886 }
784 887
785 888 static void
786 -lxi_net_static_routes(void)
889 +lxi_net_linklocal_routes(void)
787 890 {
788 - const char *cmd = "/native/usr/lib/brand/lx/routeinfo";
789 - char *const argv[] = { "routeinfo", NULL };
790 - char *const envp[] = { NULL };
791 - int code;
792 - struct stat st;
793 - char errbuf[512];
891 + lxi_run_routeinfo(lxi_net_linklocal_route);
892 +}
794 893
795 - if (stat(cmd, &st) != 0 || !S_ISREG(st.st_mode)) {
796 - /*
797 - * This binary is (potentially) shipped from another
798 - * consolidation. If it does not exist, then the platform does
799 - * not currently support static routes for LX-branded zones.
800 - */
801 - return;
802 - }
803 894
804 - /*
805 - * Run the command, firing the callback for each line that it
806 - * outputs. When this function returns, static route processing
807 - * is complete.
808 - */
809 - if (run_command(cmd, argv, envp, errbuf, sizeof (errbuf),
810 - lxi_net_static_route, &code) != 0 || code != 0) {
811 - lxi_err("failed to run \"%s\": %s", cmd, errbuf);
812 - }
895 +static void
896 +lxi_net_static_routes(void)
897 +{
898 + lxi_run_routeinfo(lxi_net_static_route);
813 899 }
814 900
815 901 static void
816 902 lxi_config_close(zone_dochandle_t handle)
817 903 {
818 904 zonecfg_fini_handle(handle);
819 905 }
820 906
821 907 static void
822 908 lxi_hook_postnet()
823 909 {
824 910 char cmd[MAXPATHLEN];
825 911 const char *zroot = zone_get_nroot();
826 912 pid_t pid;
827 913 int status;
828 914
829 915 (void) snprintf(cmd, sizeof (cmd), "%s%s", zroot, HOOK_POSTNET_PATH);
830 916 if (access(cmd, X_OK) != 0) {
831 917 /* If no suitable script is present, soldier on. */
832 918 return;
833 919 }
834 920
835 921 if ((pid = fork()) < 0) {
836 922 lxi_err("fork() failed: %s", strerror(errno));
837 923 }
838 924 if (pid == 0) {
839 925 char *const argv[] = { cmd, NULL };
840 926 char *const envp[] = { NULL };
841 927
842 928 /* wire up stderr first, in case the hook wishes to use it */
843 929 if (dup2(1, 2) < 0) {
844 930 lxi_err("dup2() failed: %s", cmd, strerror(errno));
845 931 }
846 932
847 933 /* child executes the hook */
848 934 execve(cmd, argv, envp);
849 935
850 936 /*
851 937 * Since this is running as root, access(2) is less strict than
852 938 * necessary to ensure a successful exec. If the permissions
853 939 * on the hook are busted, ignore the failure and move on.
854 940 */
855 941 if (errno == EACCES) {
856 942 exit(0);
857 943 }
858 944
859 945 lxi_err("execve(%s) failed: %s", cmd, strerror(errno));
860 946 /* NOTREACHED */
861 947 }
862 948
863 949 /* Parent waits for the hook to complete */
864 950 while (wait(&status) != pid) {
865 951 /* EMPTY */;
866 952 }
867 953 if (WIFEXITED(status)) {
868 954 if (WEXITSTATUS(status) != 0) {
869 955 lxi_err("%s[%d] exited: %d", cmd, (int)pid,
870 956 WEXITSTATUS(status));
871 957 }
872 958 } else if (WIFSIGNALED(status)) {
873 959 lxi_err("%s[%d] died on signal: %d", cmd, (int)pid,
874 960 WTERMSIG(status));
875 961 } else {
876 962 lxi_err("%s[%d] failed in unknown way", cmd, (int)pid);
877 963 }
878 964 }
879 965
880 966 static void
881 967 lxi_init_exec(char **argv)
882 968 {
883 969 const char *cmd = "/sbin/init";
884 970 char *const envp[] = { "container=zone", NULL };
885 971 int e;
886 972
887 973 argv[0] = "init";
888 974
889 975 /*
890 976 * systemd uses the 'container' env var to determine it is running
891 977 * inside a container. It only supports a few well-known types and
892 978 * treats anything else as 'other' but this is enough to make it
893 979 * behave better inside a zone. See 'detect_container' in systemd.
894 980 */
895 981 execve(cmd, argv, envp);
896 982 e = errno;
897 983
898 984 /*
899 985 * Because stdout was closed prior to exec, it must be opened again in
900 986 * the face of failure to log the error.
901 987 */
902 988 lxi_log_open();
903 989 lxi_err("execve(%s) failed: %s", cmd, strerror(e));
904 990 }
905 991
906 992 /*ARGSUSED*/
907 993 int
908 994 main(int argc, char *argv[])
909 995 {
|
↓ open down ↓ |
87 lines elided |
↑ open up ↑ |
910 996 zone_dochandle_t handle;
911 997
912 998 lxi_log_open();
913 999
914 1000 lxi_net_ipmgmtd_start();
915 1001 lxi_net_ipadm_open();
916 1002
917 1003 handle = lxi_config_open();
918 1004 lxi_net_loopback();
919 1005 lxi_net_setup(handle);
1006 +
1007 + lxi_net_linklocal_routes();
1008 + lxi_net_setup_gateways(handle);
1009 +
920 1010 lxi_config_close(handle);
921 1011
922 1012 lxi_net_static_routes();
923 1013
924 1014 lxi_net_ipadm_close();
925 1015
926 1016 lxi_hook_postnet();
927 1017
928 1018 lxi_log_close();
929 1019
930 1020 lxi_init_exec(argv);
931 1021
932 1022 /* NOTREACHED */
933 1023 return (0);
934 1024 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX