Print this page
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libipadm/common/libipadm.c
+++ new/usr/src/lib/libipadm/common/libipadm.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 (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2015 Joyent, Inc.
25 25 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
26 26 */
27 27
28 28 #include <stdio.h>
29 29 #include <stdlib.h>
30 30 #include <string.h>
31 31 #include <errno.h>
32 32 #include <fcntl.h>
33 33 #include <unistd.h>
34 34 #include <stropts.h>
35 35 #include <sys/sockio.h>
36 36 #include <sys/types.h>
37 37 #include <sys/stat.h>
38 38 #include <sys/socket.h>
39 39 #include <net/route.h>
40 40 #include <netinet/in.h>
41 41 #include <inet/ip.h>
42 42 #include <arpa/inet.h>
43 43 #include <libintl.h>
44 44 #include <libdlpi.h>
45 45 #include <libinetutil.h>
46 46 #include <libdladm.h>
47 47 #include <libdllink.h>
48 48 #include <libdliptun.h>
49 49 #include <strings.h>
50 50 #include <zone.h>
51 51 #include <ctype.h>
52 52 #include <limits.h>
53 53 #include <assert.h>
54 54 #include <netdb.h>
55 55 #include <pwd.h>
56 56 #include <auth_attr.h>
57 57 #include <secdb.h>
58 58 #include <nss_dbdefs.h>
59 59 #include "libipadm_impl.h"
60 60
61 61 /* error codes and text description */
62 62 static struct ipadm_error_info {
63 63 ipadm_status_t error_code;
64 64 const char *error_desc;
65 65 } ipadm_errors[] = {
66 66 { IPADM_SUCCESS, "Operation succeeded" },
67 67 { IPADM_FAILURE, "Operation failed" },
68 68 { IPADM_EAUTH, "Insufficient user authorizations" },
69 69 { IPADM_EPERM, "Permission denied" },
70 70 { IPADM_NO_BUFS, "No buffer space available" },
71 71 { IPADM_NO_MEMORY, "Insufficient memory" },
72 72 { IPADM_BAD_ADDR, "Invalid address" },
73 73 { IPADM_BAD_PROTOCOL, "Incorrect protocol family for operation" },
74 74 { IPADM_DAD_FOUND, "Duplicate address detected" },
75 75 { IPADM_EXISTS, "Already exists" },
76 76 { IPADM_IF_EXISTS, "Interface already exists" },
77 77 { IPADM_ADDROBJ_EXISTS, "Address object already exists" },
78 78 { IPADM_ADDRCONF_EXISTS, "Addrconf already in progress" },
79 79 { IPADM_ENXIO, "Interface does not exist" },
80 80 { IPADM_GRP_NOTEMPTY, "IPMP group is not empty" },
81 81 { IPADM_INVALID_ARG, "Invalid argument provided" },
82 82 { IPADM_INVALID_NAME, "Invalid name" },
83 83 { IPADM_DLPI_FAILURE, "Could not open DLPI link" },
84 84 { IPADM_DLADM_FAILURE, "Datalink does not exist" },
85 85 { IPADM_PROP_UNKNOWN, "Unknown property" },
86 86 { IPADM_ERANGE, "Value is outside the allowed range" },
87 87 { IPADM_ESRCH, "Value does not exist" },
88 88 { IPADM_EOVERFLOW, "Number of values exceeds the allowed limit" },
89 89 { IPADM_NOTFOUND, "Object not found" },
90 90 { IPADM_IF_INUSE, "Interface already in use" },
91 91 { IPADM_ADDR_INUSE, "Address already in use" },
92 92 { IPADM_BAD_HOSTNAME, "Hostname maps to multiple IP addresses" },
93 93 { IPADM_ADDR_NOTAVAIL, "Can't assign requested address" },
94 94 { IPADM_ALL_ADDRS_NOT_ENABLED, "All addresses could not be enabled" },
95 95 { IPADM_NDPD_NOT_RUNNING, "IPv6 autoconf daemon in.ndpd not running" },
96 96 { IPADM_DHCP_START_ERROR, "Could not start dhcpagent" },
97 97 { IPADM_DHCP_IPC_ERROR, "Could not communicate with dhcpagent" },
98 98 { IPADM_DHCP_IPC_TIMEOUT, "Communication with dhcpagent timed out" },
99 99 { IPADM_TEMPORARY_OBJ, "Persistent operation on temporary object" },
100 100 { IPADM_IPC_ERROR, "Could not communicate with ipmgmtd" },
101 101 { IPADM_NOTSUP, "Operation not supported" },
102 102 { IPADM_OP_DISABLE_OBJ, "Operation not supported on disabled object" },
103 103 { IPADM_EBADE, "Invalid data exchange with daemon" },
104 104 { IPADM_GZ_PERM, "Operation not permitted on from-gz interface"}
105 105 };
106 106
107 107 #define IPADM_NUM_ERRORS (sizeof (ipadm_errors) / sizeof (*ipadm_errors))
108 108
109 109 ipadm_status_t
110 110 ipadm_errno2status(int error)
111 111 {
112 112 switch (error) {
113 113 case 0:
114 114 return (IPADM_SUCCESS);
115 115 case ENXIO:
116 116 return (IPADM_ENXIO);
117 117 case ENOMEM:
118 118 return (IPADM_NO_MEMORY);
119 119 case ENOBUFS:
120 120 return (IPADM_NO_BUFS);
121 121 case EINVAL:
122 122 return (IPADM_INVALID_ARG);
123 123 case EBUSY:
124 124 return (IPADM_IF_INUSE);
125 125 case EEXIST:
126 126 return (IPADM_EXISTS);
127 127 case EADDRNOTAVAIL:
128 128 return (IPADM_ADDR_NOTAVAIL);
129 129 case EADDRINUSE:
130 130 return (IPADM_ADDR_INUSE);
131 131 case ENOENT:
132 132 return (IPADM_NOTFOUND);
133 133 case ERANGE:
134 134 return (IPADM_ERANGE);
135 135 case EPERM:
136 136 return (IPADM_EPERM);
137 137 case ENOTSUP:
138 138 case EOPNOTSUPP:
139 139 return (IPADM_NOTSUP);
140 140 case EBADF:
141 141 return (IPADM_IPC_ERROR);
142 142 case EBADE:
143 143 return (IPADM_EBADE);
144 144 case ESRCH:
145 145 return (IPADM_ESRCH);
146 146 case EOVERFLOW:
147 147 return (IPADM_EOVERFLOW);
148 148 default:
149 149 return (IPADM_FAILURE);
150 150 }
151 151 }
152 152
153 153 /*
154 154 * Returns a message string for the given libipadm error status.
155 155 */
156 156 const char *
157 157 ipadm_status2str(ipadm_status_t status)
158 158 {
159 159 int i;
160 160
161 161 for (i = 0; i < IPADM_NUM_ERRORS; i++) {
162 162 if (status == ipadm_errors[i].error_code)
163 163 return (dgettext(TEXT_DOMAIN,
164 164 ipadm_errors[i].error_desc));
165 165 }
166 166
167 167 return (dgettext(TEXT_DOMAIN, "<unknown error>"));
168 168 }
169 169
170 170 /*
171 171 * Opens a handle to libipadm.
172 172 * Possible values for flags:
173 173 * IPH_VRRP: Used by VRRP daemon to set the socket option SO_VRRP.
174 174 * IPH_LEGACY: This is used whenever an application needs to provide a
175 175 * logical interface name while creating or deleting
176 176 * interfaces and static addresses.
177 177 * IPH_INIT: Used by ipadm_init_prop(), to initialize protocol properties
178 178 * on reboot.
179 179 */
180 180 ipadm_status_t
181 181 ipadm_open(ipadm_handle_t *handle, uint32_t flags)
182 182 {
183 183 ipadm_handle_t iph;
184 184 ipadm_status_t status = IPADM_SUCCESS;
185 185 zoneid_t zoneid;
186 186 ushort_t zflags;
187 187 int on = B_TRUE;
188 188
189 189 if (handle == NULL)
190 190 return (IPADM_INVALID_ARG);
191 191 *handle = NULL;
192 192
193 193 if (flags & ~(IPH_VRRP|IPH_LEGACY|IPH_INIT|IPH_IPMGMTD))
194 194 return (IPADM_INVALID_ARG);
195 195
196 196 if ((iph = calloc(1, sizeof (struct ipadm_handle))) == NULL)
197 197 return (IPADM_NO_MEMORY);
198 198 iph->iph_sock = -1;
199 199 iph->iph_sock6 = -1;
200 200 iph->iph_door_fd = -1;
201 201 iph->iph_rtsock = -1;
202 202 iph->iph_flags = flags;
203 203 (void) pthread_mutex_init(&iph->iph_lock, NULL);
204 204
205 205 if ((iph->iph_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ||
206 206 (iph->iph_sock6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
207 207 goto errnofail;
208 208 }
209 209
210 210 /*
211 211 * We open a handle to libdladm here, to facilitate some daemons (like
212 212 * nwamd) which opens handle to libipadm before devfsadmd installs the
213 213 * right device permissions into the kernel and requires "all"
214 214 * privileges to open DLD_CONTROL_DEV.
215 215 *
216 216 * In a non-global shared-ip zone there will be no DLD_CONTROL_DEV node
217 217 * and dladm_open() will fail. So, we avoid this by not calling
218 218 * dladm_open() for such zones.
219 219 */
220 220 zoneid = getzoneid();
221 221 iph->iph_zoneid = zoneid;
222 222 if (zoneid != GLOBAL_ZONEID) {
223 223 if (zone_getattr(zoneid, ZONE_ATTR_FLAGS, &zflags,
224 224 sizeof (zflags)) < 0) {
225 225 goto errnofail;
226 226 }
227 227 }
228 228 if ((zoneid == GLOBAL_ZONEID) || (zflags & ZF_NET_EXCL)) {
229 229 if (dladm_open(&iph->iph_dlh) != DLADM_STATUS_OK) {
230 230 ipadm_close(iph);
231 231 return (IPADM_DLADM_FAILURE);
232 232 }
233 233 if (zoneid != GLOBAL_ZONEID) {
234 234 iph->iph_rtsock = socket(PF_ROUTE, SOCK_RAW, 0);
235 235 /*
236 236 * Failure to open rtsock is ignored as this is
237 237 * only used in non-global zones to initialize
238 238 * routing socket information.
239 239 */
240 240 }
241 241 } else {
242 242 assert(zoneid != GLOBAL_ZONEID);
243 243 iph->iph_dlh = NULL;
244 244 }
245 245 if (flags & IPH_VRRP) {
246 246 if (setsockopt(iph->iph_sock6, SOL_SOCKET, SO_VRRP, &on,
247 247 sizeof (on)) < 0 || setsockopt(iph->iph_sock, SOL_SOCKET,
248 248 SO_VRRP, &on, sizeof (on)) < 0) {
249 249 goto errnofail;
250 250 }
251 251 }
252 252 *handle = iph;
253 253 return (status);
254 254
255 255 errnofail:
256 256 status = ipadm_errno2status(errno);
257 257 ipadm_close(iph);
258 258 return (status);
259 259 }
260 260
261 261 /*
262 262 * Closes and frees the libipadm handle.
263 263 */
264 264 void
265 265 ipadm_close(ipadm_handle_t iph)
266 266 {
267 267 if (iph == NULL)
268 268 return;
269 269 if (iph->iph_sock != -1)
270 270 (void) close(iph->iph_sock);
271 271 if (iph->iph_sock6 != -1)
272 272 (void) close(iph->iph_sock6);
273 273 if (iph->iph_rtsock != -1)
274 274 (void) close(iph->iph_rtsock);
275 275 if (iph->iph_door_fd != -1)
276 276 (void) close(iph->iph_door_fd);
277 277 dladm_close(iph->iph_dlh);
278 278 (void) pthread_mutex_destroy(&iph->iph_lock);
279 279 free(iph);
280 280 }
281 281
282 282 /*
283 283 * Checks if the caller has the authorization to configure network
284 284 * interfaces.
285 285 */
286 286 boolean_t
287 287 ipadm_check_auth(void)
288 288 {
289 289 int uid;
290 290 struct passwd pwd;
291 291 char buf[NSS_BUFLEN_PASSWD];
292 292
293 293 /*
294 294 * Branded zones may have different kinds of auth, but root always
295 295 * allowed.
296 296 */
297 297 if ((uid = getuid()) == 0)
298 298 return (B_TRUE);
299 299
300 300 /* get the password entry for the given user ID */
301 301 if (getpwuid_r(uid, &pwd, buf, sizeof (buf)) == NULL)
302 302 return (B_FALSE);
303 303
304 304 /* check for presence of given authorization */
305 305 return (chkauthattr(NETWORK_INTERFACE_CONFIG_AUTH, pwd.pw_name) != 0);
306 306 }
307 307
308 308 /*
309 309 * Stores the index value of the interface in `ifname' for the address
310 310 * family `af' into the buffer pointed to by `index'.
311 311 */
312 312 static ipadm_status_t
313 313 i_ipadm_get_index(ipadm_handle_t iph, const char *ifname, sa_family_t af,
314 314 int *index)
315 315 {
316 316 struct lifreq lifr;
317 317 int sock;
318 318
319 319 bzero(&lifr, sizeof (lifr));
320 320 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
321 321 if (af == AF_INET)
322 322 sock = iph->iph_sock;
323 323 else
324 324 sock = iph->iph_sock6;
325 325
326 326 if (ioctl(sock, SIOCGLIFINDEX, (caddr_t)&lifr) < 0)
327 327 return (ipadm_errno2status(errno));
328 328 *index = lifr.lifr_index;
329 329
330 330 return (IPADM_SUCCESS);
331 331 }
332 332
333 333 /*
334 334 * Maximum amount of time (in milliseconds) to wait for Duplicate Address
335 335 * Detection to complete in the kernel.
336 336 */
337 337 #define DAD_WAIT_TIME 1000
338 338
339 339 /*
340 340 * Any time that flags are changed on an interface where either the new or the
341 341 * existing flags have IFF_UP set, we'll get a RTM_NEWADDR message to
342 342 * announce the new address added and its flag status.
343 343 * We wait here for that message and look for IFF_UP.
344 344 * If something's amiss with the kernel, though, we don't wait forever.
345 345 * (Note that IFF_DUPLICATE is a high-order bit, and we cannot see
346 346 * it in the routing socket messages.)
347 347 */
348 348 static ipadm_status_t
349 349 i_ipadm_dad_wait(ipadm_handle_t handle, const char *lifname, sa_family_t af,
350 350 int rtsock)
351 351 {
352 352 struct pollfd fds[1];
353 353 union {
354 354 struct if_msghdr ifm;
355 355 char buf[1024];
356 356 } msg;
357 357 int index;
358 358 ipadm_status_t retv;
359 359 uint64_t flags;
360 360 hrtime_t starttime, now;
361 361
362 362 fds[0].fd = rtsock;
363 363 fds[0].events = POLLIN;
364 364 fds[0].revents = 0;
365 365
366 366 retv = i_ipadm_get_index(handle, lifname, af, &index);
367 367 if (retv != IPADM_SUCCESS)
368 368 return (retv);
369 369
370 370 starttime = gethrtime();
371 371 for (;;) {
372 372 now = gethrtime();
373 373 now = (now - starttime) / 1000000;
374 374 if (now >= DAD_WAIT_TIME)
375 375 break;
376 376 if (poll(fds, 1, DAD_WAIT_TIME - (int)now) <= 0)
377 377 break;
378 378 if (read(rtsock, &msg, sizeof (msg)) <= 0)
379 379 break;
380 380 if (msg.ifm.ifm_type != RTM_NEWADDR)
381 381 continue;
382 382 /* Note that ifm_index is just 16 bits */
383 383 if (index == msg.ifm.ifm_index && (msg.ifm.ifm_flags & IFF_UP))
384 384 return (IPADM_SUCCESS);
385 385 }
386 386
387 387 retv = i_ipadm_get_flags(handle, lifname, af, &flags);
388 388 if (retv != IPADM_SUCCESS)
389 389 return (retv);
390 390 if (flags & IFF_DUPLICATE)
391 391 return (IPADM_DAD_FOUND);
392 392
393 393 return (IPADM_SUCCESS);
394 394 }
395 395
396 396 /*
397 397 * Sets the flags `on_flags' and resets the flags `off_flags' for the logical
398 398 * interface in `lifname'.
399 399 *
400 400 * If the new flags value will transition the interface from "down" to "up"
401 401 * then duplicate address detection is performed by the kernel. This routine
402 402 * waits to get the outcome of that test.
403 403 */
404 404 ipadm_status_t
405 405 i_ipadm_set_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
406 406 uint64_t on_flags, uint64_t off_flags)
407 407 {
408 408 struct lifreq lifr;
409 409 uint64_t oflags;
410 410 ipadm_status_t ret;
411 411 int rtsock = -1;
412 412 int sock, err;
413 413
414 414 ret = i_ipadm_get_flags(iph, lifname, af, &oflags);
415 415 if (ret != IPADM_SUCCESS)
416 416 return (ret);
417 417
418 418 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
419 419
420 420 /*
421 421 * Any time flags are changed on an interface that has IFF_UP set,
422 422 * we get a routing socket message. We care about the status,
423 423 * though, only when the new flags are marked "up."
424 424 */
425 425 if (!(oflags & IFF_UP) && (on_flags & IFF_UP))
426 426 rtsock = socket(PF_ROUTE, SOCK_RAW, af);
427 427
428 428 oflags |= on_flags;
429 429 oflags &= ~off_flags;
430 430 bzero(&lifr, sizeof (lifr));
431 431 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
432 432 lifr.lifr_flags = oflags;
433 433 if (ioctl(sock, SIOCSLIFFLAGS, (caddr_t)&lifr) < 0) {
434 434 err = errno;
435 435 if (rtsock != -1)
436 436 (void) close(rtsock);
437 437 return (ipadm_errno2status(err));
438 438 }
439 439 if (rtsock == -1) {
440 440 return (IPADM_SUCCESS);
441 441 } else {
442 442 /* Wait for DAD to complete. */
443 443 ret = i_ipadm_dad_wait(iph, lifname, af, rtsock);
444 444 (void) close(rtsock);
445 445 return (ret);
446 446 }
447 447 }
448 448
449 449 /*
450 450 * Returns the flags value for the logical interface in `lifname'
451 451 * in the buffer pointed to by `flags'.
452 452 */
453 453 ipadm_status_t
454 454 i_ipadm_get_flags(ipadm_handle_t iph, const char *lifname, sa_family_t af,
455 455 uint64_t *flags)
456 456 {
457 457 struct lifreq lifr;
458 458 int sock;
459 459
460 460 bzero(&lifr, sizeof (lifr));
461 461 (void) strlcpy(lifr.lifr_name, lifname, sizeof (lifr.lifr_name));
462 462 if (af == AF_INET)
463 463 sock = iph->iph_sock;
464 464 else
465 465 sock = iph->iph_sock6;
466 466
467 467 if (ioctl(sock, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
468 468 return (ipadm_errno2status(errno));
469 469 }
470 470 *flags = lifr.lifr_flags;
471 471
472 472 return (IPADM_SUCCESS);
473 473 }
474 474
475 475 /*
476 476 * Determines whether or not an interface name represents a loopback
477 477 * interface, before the interface has been plumbed.
478 478 * It is assumed that the interface name in `ifname' is of correct format
479 479 * as verified by ifparse_ifspec().
480 480 *
481 481 * Returns: B_TRUE if loopback, B_FALSE if not.
482 482 */
483 483 boolean_t
484 484 i_ipadm_is_loopback(const char *ifname)
485 485 {
486 486 int len = strlen(LOOPBACK_IF);
487 487
488 488 return (strncmp(ifname, LOOPBACK_IF, len) == 0 &&
489 489 (ifname[len] == '\0' || ifname[len] == IPADM_LOGICAL_SEP));
490 490 }
491 491
492 492 /*
493 493 * Determines whether or not an interface name represents a vni
494 494 * interface, before the interface has been plumbed.
495 495 * It is assumed that the interface name in `ifname' is of correct format
496 496 * as verified by ifparse_ifspec().
497 497 *
498 498 * Returns: B_TRUE if vni, B_FALSE if not.
499 499 */
500 500 boolean_t
501 501 i_ipadm_is_vni(const char *ifname)
502 502 {
503 503 ifspec_t ifsp;
504 504
505 505 return (ifparse_ifspec(ifname, &ifsp) &&
506 506 strcmp(ifsp.ifsp_devnm, "vni") == 0);
507 507 }
508 508
509 509 /*
510 510 * Returns B_TRUE if `ifname' is an IP interface on a 6to4 tunnel.
511 511 */
512 512 boolean_t
513 513 i_ipadm_is_6to4(ipadm_handle_t iph, char *ifname)
514 514 {
515 515 dladm_status_t dlstatus;
516 516 datalink_class_t class;
517 517 iptun_params_t params;
518 518 datalink_id_t linkid;
519 519
520 520 if (iph->iph_dlh == NULL) {
521 521 assert(iph->iph_zoneid != GLOBAL_ZONEID);
522 522 return (B_FALSE);
523 523 }
524 524 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid, NULL,
525 525 &class, NULL);
526 526 if (dlstatus == DLADM_STATUS_OK && class == DATALINK_CLASS_IPTUN) {
527 527 params.iptun_param_linkid = linkid;
528 528 dlstatus = dladm_iptun_getparams(iph->iph_dlh, ¶ms,
529 529 DLADM_OPT_ACTIVE);
530 530 if (dlstatus == DLADM_STATUS_OK &&
531 531 params.iptun_param_type == IPTUN_TYPE_6TO4) {
532 532 return (B_TRUE);
533 533 }
534 534 }
535 535 return (B_FALSE);
536 536 }
537 537
538 538 /*
539 539 * Returns B_TRUE if `ifname' represents an IPMP underlying interface.
540 540 */
541 541 boolean_t
542 542 i_ipadm_is_under_ipmp(ipadm_handle_t iph, const char *ifname)
543 543 {
544 544 struct lifreq lifr;
545 545
546 546 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
547 547 if (ioctl(iph->iph_sock, SIOCGLIFGROUPNAME, (caddr_t)&lifr) < 0) {
548 548 if (ioctl(iph->iph_sock6, SIOCGLIFGROUPNAME,
549 549 (caddr_t)&lifr) < 0) {
550 550 return (B_FALSE);
551 551 }
552 552 }
553 553 return (lifr.lifr_groupname[0] != '\0');
554 554 }
555 555
556 556 /*
557 557 * Returns B_TRUE if `ifname' represents an IPMP meta-interface.
558 558 */
559 559 boolean_t
560 560 i_ipadm_is_ipmp(ipadm_handle_t iph, const char *ifname)
561 561 {
562 562 uint64_t flags;
563 563
564 564 if (i_ipadm_get_flags(iph, ifname, AF_INET, &flags) != IPADM_SUCCESS &&
565 565 i_ipadm_get_flags(iph, ifname, AF_INET6, &flags) != IPADM_SUCCESS)
566 566 return (B_FALSE);
567 567
568 568 return ((flags & IFF_IPMP) != 0);
569 569 }
570 570
571 571 /*
572 572 * For a given interface name, ipadm_if_enabled() checks if v4
573 573 * or v6 or both IP interfaces exist in the active configuration.
574 574 */
575 575 boolean_t
576 576 ipadm_if_enabled(ipadm_handle_t iph, const char *ifname, sa_family_t af)
577 577 {
578 578 struct lifreq lifr;
579 579 int s4 = iph->iph_sock;
580 580 int s6 = iph->iph_sock6;
581 581
582 582 bzero(&lifr, sizeof (lifr));
583 583 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
584 584 switch (af) {
585 585 case AF_INET:
586 586 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
587 587 return (B_TRUE);
588 588 break;
589 589 case AF_INET6:
590 590 if (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0)
591 591 return (B_TRUE);
592 592 break;
593 593 case AF_UNSPEC:
594 594 if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0 ||
595 595 ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifr) == 0) {
596 596 return (B_TRUE);
597 597 }
598 598 }
599 599 return (B_FALSE);
600 600 }
601 601
602 602 /*
603 603 * Apply the interface property by retrieving information from nvl.
604 604 */
605 605 static ipadm_status_t
606 606 i_ipadm_init_ifprop(ipadm_handle_t iph, nvlist_t *nvl)
607 607 {
608 608 nvpair_t *nvp;
609 609 char *name, *pname = NULL;
610 610 char *protostr = NULL, *ifname = NULL, *pval = NULL;
611 611 uint_t proto;
612 612 int err = 0;
613 613
614 614 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
615 615 nvp = nvlist_next_nvpair(nvl, nvp)) {
616 616 name = nvpair_name(nvp);
617 617 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
618 618 if ((err = nvpair_value_string(nvp, &ifname)) != 0)
619 619 break;
620 620 } else if (strcmp(name, IPADM_NVP_PROTONAME) == 0) {
621 621 if ((err = nvpair_value_string(nvp, &protostr)) != 0)
622 622 break;
623 623 } else {
624 624 assert(!IPADM_PRIV_NVP(name));
625 625 pname = name;
626 626 if ((err = nvpair_value_string(nvp, &pval)) != 0)
627 627 break;
628 628 }
629 629 }
630 630 if (err != 0)
631 631 return (ipadm_errno2status(err));
632 632 proto = ipadm_str2proto(protostr);
633 633 return (ipadm_set_ifprop(iph, ifname, pname, pval, proto,
634 634 IPADM_OPT_ACTIVE));
635 635 }
636 636
637 637 /*
638 638 * Instantiate the address object or set the address object property by
639 639 * retrieving the configuration from the nvlist `nvl'.
640 640 */
641 641 ipadm_status_t
642 642 i_ipadm_init_addrobj(ipadm_handle_t iph, nvlist_t *nvl)
643 643 {
644 644 nvpair_t *nvp;
645 645 char *name;
646 646 char *aobjname = NULL, *pval = NULL, *ifname = NULL;
647 647 sa_family_t af = AF_UNSPEC;
648 648 ipadm_addr_type_t atype = IPADM_ADDR_NONE;
649 649 int err = 0;
650 650 ipadm_status_t status = IPADM_SUCCESS;
651 651
652 652 for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
653 653 nvp = nvlist_next_nvpair(nvl, nvp)) {
654 654 name = nvpair_name(nvp);
655 655 if (strcmp(name, IPADM_NVP_IFNAME) == 0) {
656 656 if ((err = nvpair_value_string(nvp, &ifname)) != 0)
657 657 break;
658 658 } else if (strcmp(name, IPADM_NVP_AOBJNAME) == 0) {
659 659 if ((err = nvpair_value_string(nvp, &aobjname)) != 0)
660 660 break;
661 661 } else if (i_ipadm_name2atype(name, &af, &atype)) {
662 662 break;
663 663 } else {
664 664 assert(!IPADM_PRIV_NVP(name));
665 665 err = nvpair_value_string(nvp, &pval);
666 666 break;
667 667 }
668 668 }
669 669 if (err != 0)
670 670 return (ipadm_errno2status(err));
671 671
672 672 switch (atype) {
673 673 case IPADM_ADDR_STATIC:
674 674 status = i_ipadm_enable_static(iph, ifname, nvl, af);
675 675 break;
676 676 case IPADM_ADDR_DHCP:
677 677 status = i_ipadm_enable_dhcp(iph, ifname, nvl);
678 678 if (status == IPADM_DHCP_IPC_TIMEOUT)
679 679 status = IPADM_SUCCESS;
680 680 break;
681 681 case IPADM_ADDR_IPV6_ADDRCONF:
682 682 status = i_ipadm_enable_addrconf(iph, ifname, nvl);
683 683 break;
684 684 case IPADM_ADDR_NONE:
685 685 status = ipadm_set_addrprop(iph, name, pval, aobjname,
686 686 IPADM_OPT_ACTIVE);
687 687 break;
688 688 }
689 689
690 690 return (status);
691 691 }
692 692
693 693 /*
694 694 * Instantiate the interface object by retrieving the configuration from
695 695 * `ifnvl'. The nvlist `ifnvl' contains all the persistent configuration
696 696 * (interface properties and address objects on that interface) for the
697 697 * given `ifname'.
698 698 */
699 699 ipadm_status_t
700 700 i_ipadm_init_ifobj(ipadm_handle_t iph, const char *ifname, nvlist_t *ifnvl)
701 701 {
702 702 nvlist_t *nvl = NULL;
703 703 nvpair_t *nvp;
704 704 char *afstr;
705 705 ipadm_status_t status;
706 706 ipadm_status_t ret_status = IPADM_SUCCESS;
707 707 char newifname[LIFNAMSIZ];
708 708 char *aobjstr;
709 709 sa_family_t af = AF_UNSPEC;
710 710 boolean_t is_ngz = (iph->iph_zoneid != GLOBAL_ZONEID);
711 711
712 712 (void) strlcpy(newifname, ifname, sizeof (newifname));
713 713 /*
714 714 * First plumb the given interface and then apply all the persistent
715 715 * interface properties and then instantiate any persistent addresses
716 716 * objects on that interface.
717 717 */
718 718 for (nvp = nvlist_next_nvpair(ifnvl, NULL); nvp != NULL;
719 719 nvp = nvlist_next_nvpair(ifnvl, nvp)) {
720 720 if (nvpair_value_nvlist(nvp, &nvl) != 0)
721 721 continue;
722 722
723 723 if (nvlist_lookup_string(nvl, IPADM_NVP_FAMILY, &afstr) == 0) {
724 724 status = i_ipadm_plumb_if(iph, newifname, atoi(afstr),
725 725 IPADM_OPT_ACTIVE);
726 726 /*
727 727 * If the interface is already plumbed, we should
728 728 * ignore this error because there might be address
729 729 * address objects on that interface that needs to
730 730 * be enabled again.
731 731 */
732 732 if (status == IPADM_IF_EXISTS)
733 733 status = IPADM_SUCCESS;
734 734
735 735 if (is_ngz)
736 736 af = atoi(afstr);
737 737 } else if (nvlist_lookup_string(nvl, IPADM_NVP_AOBJNAME,
738 738 &aobjstr) == 0) {
739 739 /*
740 740 * For a static address, we need to search for
741 741 * the prefixlen in the nvlist `ifnvl'.
742 742 */
743 743 if (nvlist_exists(nvl, IPADM_NVP_IPV4ADDR) ||
744 744 nvlist_exists(nvl, IPADM_NVP_IPV6ADDR)) {
745 745 status = i_ipadm_merge_prefixlen_from_nvl(ifnvl,
746 746 nvl, aobjstr);
747 747 if (status != IPADM_SUCCESS)
748 748 continue;
749 749 }
750 750 status = i_ipadm_init_addrobj(iph, nvl);
751 751 /*
752 752 * If this address is in use on some other interface,
753 753 * we want to record an error to be returned as
754 754 * a soft error and continue processing the rest of
755 755 * the addresses.
756 756 */
757 757 if (status == IPADM_ADDR_NOTAVAIL) {
758 758 ret_status = IPADM_ALL_ADDRS_NOT_ENABLED;
759 759 status = IPADM_SUCCESS;
760 760 }
761 761 } else {
762 762 assert(nvlist_exists(nvl, IPADM_NVP_PROTONAME));
763 763 status = i_ipadm_init_ifprop(iph, nvl);
764 764 }
765 765 if (status != IPADM_SUCCESS)
766 766 return (status);
767 767 }
768 768
769 769 if (is_ngz && af != AF_UNSPEC)
770 770 ret_status = ipadm_init_net_from_gz(iph, newifname, NULL);
771 771 return (ret_status);
772 772 }
773 773
774 774 /*
775 775 * Retrieves the persistent configuration for the given interface(s) in `ifs'
776 776 * by contacting the daemon and dumps the information in `allifs'.
777 777 */
778 778 ipadm_status_t
779 779 i_ipadm_init_ifs(ipadm_handle_t iph, const char *ifs, nvlist_t **allifs)
780 780 {
781 781 nvlist_t *nvl = NULL;
782 782 size_t nvlsize, bufsize;
783 783 ipmgmt_initif_arg_t *iargp;
784 784 char *buf = NULL, *nvlbuf = NULL;
785 785 ipmgmt_get_rval_t *rvalp = NULL;
786 786 int err;
787 787 ipadm_status_t status = IPADM_SUCCESS;
788 788
789 789 if ((err = ipadm_str2nvlist(ifs, &nvl, IPADM_NORVAL)) != 0)
790 790 return (ipadm_errno2status(err));
791 791
792 792 err = nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE, 0);
793 793 if (err != 0) {
794 794 status = ipadm_errno2status(err);
795 795 goto done;
796 796 }
797 797 bufsize = sizeof (*iargp) + nvlsize;
798 798 if ((buf = malloc(bufsize)) == NULL) {
799 799 status = ipadm_errno2status(errno);
800 800 goto done;
801 801 }
802 802
803 803 /* populate the door_call argument structure */
804 804 iargp = (void *)buf;
805 805 iargp->ia_cmd = IPMGMT_CMD_INITIF;
806 806 iargp->ia_flags = 0;
807 807 iargp->ia_family = AF_UNSPEC;
808 808 iargp->ia_nvlsize = nvlsize;
809 809 (void) bcopy(nvlbuf, buf + sizeof (*iargp), nvlsize);
810 810
811 811 if ((rvalp = malloc(sizeof (ipmgmt_get_rval_t))) == NULL) {
812 812 status = ipadm_errno2status(errno);
813 813 goto done;
814 814 }
815 815 if ((err = ipadm_door_call(iph, iargp, bufsize, (void **)&rvalp,
816 816 sizeof (*rvalp), B_TRUE)) != 0) {
817 817 status = ipadm_errno2status(err);
818 818 goto done;
819 819 }
820 820
821 821 /*
822 822 * Daemon reply pointed to by rvalp contains ipmgmt_get_rval_t structure
823 823 * followed by a list of packed nvlists, each of which represents
824 824 * configuration information for the given interface(s).
825 825 */
826 826 err = nvlist_unpack((char *)rvalp + sizeof (ipmgmt_get_rval_t),
827 827 rvalp->ir_nvlsize, allifs, NV_ENCODE_NATIVE);
828 828 if (err != 0)
829 829 status = ipadm_errno2status(err);
830 830 done:
831 831 nvlist_free(nvl);
832 832 free(buf);
833 833 free(nvlbuf);
834 834 free(rvalp);
835 835 return (status);
836 836 }
837 837
838 838 /*
839 839 * Returns B_FALSE if
840 840 * (1) `ifname' is NULL or has no string or has a string of invalid length
841 841 * (2) ifname is a logical interface and IPH_LEGACY is not set, or
842 842 */
843 843 boolean_t
844 844 i_ipadm_validate_ifname(ipadm_handle_t iph, const char *ifname)
845 845 {
846 846 ifspec_t ifsp;
847 847
848 848 if (ifname == NULL || ifname[0] == '\0' ||
849 849 !ifparse_ifspec(ifname, &ifsp))
850 850 return (B_FALSE);
851 851 if (ifsp.ifsp_lunvalid)
852 852 return (ifsp.ifsp_lun > 0 && (iph->iph_flags & IPH_LEGACY));
853 853 return (B_TRUE);
854 854 }
855 855
856 856 /*
857 857 * Wrapper for sending a non-transparent I_STR ioctl().
858 858 * Returns: Result from ioctl().
859 859 */
860 860 int
861 861 i_ipadm_strioctl(int s, int cmd, char *buf, int buflen)
862 862 {
863 863 struct strioctl ioc;
864 864
865 865 (void) memset(&ioc, 0, sizeof (ioc));
866 866 ioc.ic_cmd = cmd;
867 867 ioc.ic_timout = 0;
868 868 ioc.ic_len = buflen;
869 869 ioc.ic_dp = buf;
870 870
871 871 return (ioctl(s, I_STR, (char *)&ioc));
872 872 }
873 873
874 874 /*
875 875 * Make a door call to the server and checks if the door call succeeded or not.
876 876 * `is_varsize' specifies that the data returned by ipmgmtd daemon is of
877 877 * variable size and door will allocate buffer using mmap(). In such cases
878 878 * we re-allocate the required memory,n assign it to `rbufp', copy the data to
879 879 * `rbufp' and then call munmap() (see below).
880 880 *
881 881 * It also checks to see if the server side procedure ran successfully by
882 882 * checking for ir_err. Therefore, for some callers who just care about the
883 883 * return status can set `rbufp' to NULL and set `rsize' to 0.
884 884 */
885 885 int
886 886 ipadm_door_call(ipadm_handle_t iph, void *arg, size_t asize, void **rbufp,
887 887 size_t rsize, boolean_t is_varsize)
888 888 {
889 889 door_arg_t darg;
890 890 int err;
891 891 ipmgmt_retval_t rval, *rvalp;
892 892 boolean_t reopen = B_FALSE;
893 893
894 894 if (rbufp == NULL) {
895 895 rvalp = &rval;
896 896 rbufp = (void **)&rvalp;
897 897 rsize = sizeof (rval);
898 898 }
899 899
900 900 darg.data_ptr = arg;
901 901 darg.data_size = asize;
902 902 darg.desc_ptr = NULL;
903 903 darg.desc_num = 0;
904 904 darg.rbuf = *rbufp;
905 905 darg.rsize = rsize;
906 906
907 907 reopen:
908 908 (void) pthread_mutex_lock(&iph->iph_lock);
909 909 /*
910 910 * The door descriptor is opened if it isn't already.
911 911 */
912 912 if (iph->iph_door_fd == -1) {
913 913 char door[MAXPATHLEN];
914 914 const char *zroot = zone_get_nroot();
915 915
916 916 /*
917 917 * If this is a branded zone, make sure we use the "/native"
918 918 * prefix for the door path:
919 919 */
920 920 (void) snprintf(door, sizeof (door), "%s%s", zroot != NULL ?
921 921 zroot : "", IPMGMT_DOOR);
922 922
923 923 if ((iph->iph_door_fd = open(door, O_RDONLY)) < 0) {
924 924 err = errno;
925 925 (void) pthread_mutex_unlock(&iph->iph_lock);
926 926 return (err);
927 927 }
928 928 }
929 929 (void) pthread_mutex_unlock(&iph->iph_lock);
930 930
931 931 if (door_call(iph->iph_door_fd, &darg) == -1) {
932 932 /*
933 933 * Stale door descriptor is possible if ipmgmtd was restarted
934 934 * since last iph_door_fd was opened, so try re-opening door
935 935 * descriptor.
936 936 */
937 937 if (!reopen && errno == EBADF) {
938 938 (void) close(iph->iph_door_fd);
939 939 iph->iph_door_fd = -1;
940 940 reopen = B_TRUE;
941 941 goto reopen;
942 942 }
943 943 return (errno);
944 944 }
945 945 err = ((ipmgmt_retval_t *)(void *)(darg.rbuf))->ir_err;
946 946 if (darg.rbuf != *rbufp) {
947 947 /*
948 948 * if the caller is expecting the result to fit in specified
949 949 * buffer then return failure.
950 950 */
951 951 if (!is_varsize)
952 952 err = EBADE;
953 953 /*
954 954 * The size of the buffer `*rbufp' was not big enough
955 955 * and the door itself allocated buffer, for us. We will
956 956 * hit this, on several occasion as for some cases
957 957 * we cannot predict the size of the return structure.
958 958 * Reallocate the buffer `*rbufp' and memcpy() the contents
959 959 * to new buffer.
960 960 */
961 961 if (err == 0) {
962 962 void *newp;
963 963
964 964 /* allocated memory will be freed by the caller */
965 965 if ((newp = realloc(*rbufp, darg.rsize)) == NULL) {
966 966 err = ENOMEM;
967 967 } else {
968 968 *rbufp = newp;
969 969 (void) memcpy(*rbufp, darg.rbuf, darg.rsize);
970 970 }
971 971 }
972 972 /* munmap() the door buffer */
973 973 (void) munmap(darg.rbuf, darg.rsize);
974 974 } else {
975 975 if (darg.rsize != rsize)
976 976 err = EBADE;
977 977 }
978 978 return (err);
979 979 }
|
↓ open down ↓ |
979 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX