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