8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libipadm / common / ipadm_if.c
blob41f22e4eeb460ab89e52be11cc86b385d5594dc5
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <errno.h>
26 #include <sys/sockio.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <unistd.h>
30 #include <stropts.h>
31 #include <strings.h>
32 #include <libdlpi.h>
33 #include <libdllink.h>
34 #include <libinetutil.h>
35 #include <inet/ip.h>
36 #include <limits.h>
37 #include <zone.h>
38 #include <ipadm_ndpd.h>
39 #include "libipadm_impl.h"
41 static ipadm_status_t i_ipadm_slifname_arp(char *, uint64_t, int);
42 static ipadm_status_t i_ipadm_slifname(ipadm_handle_t, char *, char *,
43 uint64_t, int, uint32_t);
44 static ipadm_status_t i_ipadm_create_ipmp_peer(ipadm_handle_t, char *,
45 sa_family_t);
46 static ipadm_status_t i_ipadm_persist_if(ipadm_handle_t, const char *,
47 sa_family_t);
50 * Returns B_FALSE if the interface in `ifname' has at least one address that is
51 * IFF_UP in the addresses in `ifa'.
53 static boolean_t
54 i_ipadm_is_if_down(char *ifname, struct ifaddrs *ifa)
56 struct ifaddrs *ifap;
57 char cifname[LIFNAMSIZ];
58 char *sep;
60 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
61 (void) strlcpy(cifname, ifap->ifa_name, sizeof (cifname));
62 if ((sep = strrchr(cifname, IPADM_LOGICAL_SEP)) != NULL)
63 *sep = '\0';
65 * If this condition is true, there is at least one
66 * address that is IFF_UP. So, we need to return B_FALSE.
68 if (strcmp(cifname, ifname) == 0 &&
69 (ifap->ifa_flags & IFF_UP)) {
70 return (B_FALSE);
73 /* We did not find any IFF_UP addresses. */
74 return (B_TRUE);
78 * Retrieves the information for the interface `ifname' from active
79 * config if `ifname' is specified and returns the result in the list `if_info'.
80 * Otherwise, it retrieves the information for all the interfaces in
81 * the active config and returns the result in the list `if_info'.
83 static ipadm_status_t
84 i_ipadm_active_if_info(ipadm_handle_t iph, const char *ifname,
85 ipadm_if_info_t **if_info, int64_t lifc_flags)
87 struct lifreq *buf;
88 struct lifreq *lifrp;
89 struct lifreq lifrl;
90 ipadm_if_info_t *last = NULL;
91 ipadm_if_info_t *ifp;
92 int s;
93 int n;
94 int numifs;
95 ipadm_status_t status;
97 *if_info = NULL;
99 * Get information for all interfaces.
101 if (getallifs(iph->iph_sock, 0, &buf, &numifs, lifc_flags) != 0)
102 return (ipadm_errno2status(errno));
104 lifrp = buf;
105 for (n = 0; n < numifs; n++, lifrp++) {
106 /* Skip interfaces with logical num != 0 */
107 if (i_ipadm_get_lnum(lifrp->lifr_name) != 0)
108 continue;
110 * Skip the current interface if a specific `ifname' has
111 * been requested and current interface does not match
112 * `ifname'.
114 if (ifname != NULL && strcmp(lifrp->lifr_name, ifname) != 0)
115 continue;
117 * Check if the interface already exists in our list.
118 * If it already exists, we need to update its flags.
120 for (ifp = *if_info; ifp != NULL; ifp = ifp->ifi_next) {
121 if (strcmp(lifrp->lifr_name, ifp->ifi_name) == 0)
122 break;
124 if (ifp == NULL) {
125 ifp = calloc(1, sizeof (ipadm_if_info_t));
126 if (ifp == NULL) {
127 status = ipadm_errno2status(errno);
128 goto fail;
130 (void) strlcpy(ifp->ifi_name, lifrp->lifr_name,
131 sizeof (ifp->ifi_name));
132 /* Update the `ifi_next' pointer for this new node */
133 if (*if_info == NULL)
134 *if_info = ifp;
135 else
136 last->ifi_next = ifp;
137 last = ifp;
141 * Retrieve the flags for the interface by doing a
142 * SIOCGLIFFLAGS to populate the `ifi_cflags' field.
144 (void) strlcpy(lifrl.lifr_name,
145 lifrp->lifr_name, sizeof (lifrl.lifr_name));
146 s = (lifrp->lifr_addr.ss_family == AF_INET) ?
147 iph->iph_sock : iph->iph_sock6;
148 if (ioctl(s, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)
149 continue;
150 if (lifrl.lifr_flags & IFF_BROADCAST)
151 ifp->ifi_cflags |= IFIF_BROADCAST;
152 if (lifrl.lifr_flags & IFF_MULTICAST)
153 ifp->ifi_cflags |= IFIF_MULTICAST;
154 if (lifrl.lifr_flags & IFF_POINTOPOINT)
155 ifp->ifi_cflags |= IFIF_POINTOPOINT;
156 if (lifrl.lifr_flags & IFF_VIRTUAL)
157 ifp->ifi_cflags |= IFIF_VIRTUAL;
158 if (lifrl.lifr_flags & IFF_IPMP)
159 ifp->ifi_cflags |= IFIF_IPMP;
160 if (lifrl.lifr_flags & IFF_STANDBY)
161 ifp->ifi_cflags |= IFIF_STANDBY;
162 if (lifrl.lifr_flags & IFF_INACTIVE)
163 ifp->ifi_cflags |= IFIF_INACTIVE;
164 if (lifrl.lifr_flags & IFF_VRRP)
165 ifp->ifi_cflags |= IFIF_VRRP;
166 if (lifrl.lifr_flags & IFF_NOACCEPT)
167 ifp->ifi_cflags |= IFIF_NOACCEPT;
168 if (lifrl.lifr_flags & IFF_IPV4)
169 ifp->ifi_cflags |= IFIF_IPV4;
170 if (lifrl.lifr_flags & IFF_IPV6)
171 ifp->ifi_cflags |= IFIF_IPV6;
172 if (lifrl.lifr_flags & IFF_L3PROTECT)
173 ifp->ifi_cflags |= IFIF_L3PROTECT;
175 free(buf);
176 return (IPADM_SUCCESS);
177 fail:
178 free(buf);
179 ipadm_free_if_info(*if_info);
180 *if_info = NULL;
181 return (status);
185 * Returns the interface information for `ifname' in `if_info' from persistent
186 * config if `ifname' is non-null. Otherwise, it returns all the interfaces
187 * from persistent config in `if_info'.
189 static ipadm_status_t
190 i_ipadm_persist_if_info(ipadm_handle_t iph, const char *ifname,
191 ipadm_if_info_t **if_info)
193 ipadm_status_t status = IPADM_SUCCESS;
194 ipmgmt_getif_arg_t getif;
195 ipmgmt_getif_rval_t *rvalp;
196 ipadm_if_info_t *ifp, *curr, *prev = NULL;
197 int i = 0, err = 0;
199 bzero(&getif, sizeof (getif));
200 if (ifname != NULL)
201 (void) strlcpy(getif.ia_ifname, ifname, LIFNAMSIZ);
202 getif.ia_cmd = IPMGMT_CMD_GETIF;
204 *if_info = NULL;
206 if ((rvalp = malloc(sizeof (ipmgmt_getif_rval_t))) == NULL)
207 return (ipadm_errno2status(errno));
208 err = ipadm_door_call(iph, &getif, sizeof (getif), (void **)&rvalp,
209 sizeof (*rvalp), B_TRUE);
210 if (err == ENOENT) {
211 free(rvalp);
212 if (ifname != NULL)
213 return (ipadm_errno2status(err));
214 return (IPADM_SUCCESS);
215 } else if (err != 0) {
216 free(rvalp);
217 return (ipadm_errno2status(err));
220 ifp = rvalp->ir_ifinfo;
221 for (i = 0; i < rvalp->ir_ifcnt; i++) {
222 ifp = rvalp->ir_ifinfo + i;
223 if ((curr = malloc(sizeof (*curr))) == NULL) {
224 status = ipadm_errno2status(errno);
225 ipadm_free_if_info(prev);
226 break;
228 (void) bcopy(ifp, curr, sizeof (*curr));
229 curr->ifi_next = prev;
230 prev = curr;
232 *if_info = curr;
233 free(rvalp);
234 return (status);
238 * Collects information for `ifname' if one is specified from both
239 * active and persistent config in `if_info'. If no `ifname' is specified,
240 * this returns all the interfaces in active and persistent config in
241 * `if_info'.
243 ipadm_status_t
244 i_ipadm_get_all_if_info(ipadm_handle_t iph, const char *ifname,
245 ipadm_if_info_t **if_info, int64_t lifc_flags)
247 ipadm_status_t status;
248 ipadm_if_info_t *aifinfo = NULL;
249 ipadm_if_info_t *pifinfo = NULL;
250 ipadm_if_info_t *aifp;
251 ipadm_if_info_t *pifp;
252 ipadm_if_info_t *last = NULL;
253 struct ifaddrs *ifa;
254 struct ifaddrs *ifap;
257 * Retrive the information for the requested `ifname' or all
258 * interfaces from active configuration.
260 retry:
261 status = i_ipadm_active_if_info(iph, ifname, &aifinfo, lifc_flags);
262 if (status != IPADM_SUCCESS)
263 return (status);
264 /* Get the interface state for each interface in `aifinfo'. */
265 if (aifinfo != NULL) {
266 /* We need all addresses to get the interface state */
267 if (getallifaddrs(AF_UNSPEC, &ifa, (LIFC_NOXMIT|LIFC_TEMPORARY|
268 LIFC_ALLZONES|LIFC_UNDER_IPMP)) != 0) {
269 status = ipadm_errno2status(errno);
270 goto fail;
272 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
274 * Find the `ifaddrs' structure from `ifa'
275 * for this interface. We need the IFF_* flags
276 * to find the interface state.
278 for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
279 if (strcmp(ifap->ifa_name, aifp->ifi_name) == 0)
280 break;
282 if (ifap == NULL) {
284 * The interface might have been removed
285 * from kernel. Retry getting all the active
286 * interfaces.
288 freeifaddrs(ifa);
289 ipadm_free_if_info(aifinfo);
290 aifinfo = NULL;
291 goto retry;
293 if (!(ifap->ifa_flags & IFF_RUNNING) ||
294 (ifap->ifa_flags & IFF_FAILED))
295 aifp->ifi_state = IFIS_FAILED;
296 else if (ifap->ifa_flags & IFF_OFFLINE)
297 aifp->ifi_state = IFIS_OFFLINE;
298 else if (i_ipadm_is_if_down(aifp->ifi_name, ifa))
299 aifp->ifi_state = IFIS_DOWN;
300 else
301 aifp->ifi_state = IFIS_OK;
302 if (aifp->ifi_next == NULL)
303 last = aifp;
305 freeifaddrs(ifa);
308 * Get the persistent interface information in `pifinfo'.
310 status = i_ipadm_persist_if_info(iph, ifname, &pifinfo);
311 if (status == IPADM_NOTFOUND) {
312 *if_info = aifinfo;
313 return (IPADM_SUCCESS);
315 if (status != IPADM_SUCCESS)
316 goto fail;
318 * If a persistent interface is also found in `aifinfo', update
319 * its entry in `aifinfo' with the persistent information from
320 * `pifinfo'. If an interface is found in `pifinfo', but not in
321 * `aifinfo', it means that this interface was disabled. We should
322 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
324 for (pifp = pifinfo; pifp != NULL; pifp = pifp->ifi_next) {
325 for (aifp = aifinfo; aifp != NULL; aifp = aifp->ifi_next) {
326 if (strcmp(aifp->ifi_name, pifp->ifi_name) == 0) {
327 aifp->ifi_pflags = pifp->ifi_pflags;
328 break;
331 if (aifp == NULL) {
332 aifp = malloc(sizeof (ipadm_if_info_t));
333 if (aifp == NULL) {
334 status = ipadm_errno2status(errno);
335 goto fail;
337 *aifp = *pifp;
338 aifp->ifi_next = NULL;
339 aifp->ifi_state = IFIS_DISABLED;
340 if (last != NULL)
341 last->ifi_next = aifp;
342 else
343 aifinfo = aifp;
344 last = aifp;
347 *if_info = aifinfo;
348 ipadm_free_if_info(pifinfo);
349 return (IPADM_SUCCESS);
350 fail:
351 *if_info = NULL;
352 ipadm_free_if_info(aifinfo);
353 ipadm_free_if_info(pifinfo);
354 return (status);
358 i_ipadm_get_lnum(const char *ifname)
360 char *num = strrchr(ifname, IPADM_LOGICAL_SEP);
362 if (num == NULL)
363 return (0);
365 return (atoi(++num));
369 * Sets the output argument `exists' to true or false based on whether
370 * any persistent configuration is available for `ifname' and returns
371 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
372 * `exists' is unmodified and an error status is returned.
374 ipadm_status_t
375 i_ipadm_if_pexists(ipadm_handle_t iph, const char *ifname, sa_family_t af,
376 boolean_t *exists)
378 ipadm_if_info_t *ifinfo;
379 ipadm_status_t status;
382 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
383 * knows about persistent configuration in the first place, so we
384 * just return success.
386 if (iph->iph_flags & IPH_IPMGMTD) {
387 *exists = B_FALSE;
388 return (IPADM_SUCCESS);
390 status = i_ipadm_persist_if_info(iph, ifname, &ifinfo);
391 if (status == IPADM_SUCCESS) {
392 *exists = ((af == AF_INET &&
393 (ifinfo->ifi_pflags & IFIF_IPV4)) ||
394 (af == AF_INET6 &&
395 (ifinfo->ifi_pflags & IFIF_IPV6)));
396 free(ifinfo);
397 } else if (status == IPADM_NOTFOUND) {
398 status = IPADM_SUCCESS;
399 *exists = B_FALSE;
401 return (status);
405 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
406 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
407 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
408 * the bottom of the stream for tunneling interfaces.
410 ipadm_status_t
411 ipadm_open_arp_on_udp(const char *udp_dev_name, int *fd)
413 int err;
415 if ((*fd = open(udp_dev_name, O_RDWR)) == -1)
416 return (ipadm_errno2status(errno));
419 * Pop off all undesired modules (note that the user may have
420 * configured autopush to add modules above udp), and push the
421 * arp module onto the resulting stream. This is used to make
422 * IP+ARP be able to atomically track the muxid for the I_PLINKed
423 * STREAMS, thus it isn't related to ARP running the ARP protocol.
425 while (ioctl(*fd, I_POP, 0) != -1)
427 if (errno == EINVAL && ioctl(*fd, I_PUSH, ARP_MOD_NAME) != -1)
428 return (IPADM_SUCCESS);
429 err = errno;
430 (void) close(*fd);
432 return (ipadm_errno2status(err));
436 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an
437 * underlying interface in an ipmp group G is plumbed for an address family,
438 * but the meta-interface for the other address family `af' does not exist
439 * yet for the group G. If `af' is IPv6, we need to bring up the
440 * link-local address.
442 static ipadm_status_t
443 i_ipadm_create_ipmp(ipadm_handle_t iph, char *ifname, sa_family_t af,
444 const char *grname, uint32_t ipadm_flags)
446 ipadm_status_t status;
447 struct lifreq lifr;
448 int sock;
449 int err;
451 assert(ipadm_flags & IPADM_OPT_IPMP);
453 /* Create the ipmp underlying interface */
454 status = i_ipadm_create_if(iph, ifname, af, ipadm_flags);
455 if (status != IPADM_SUCCESS && status != IPADM_IF_EXISTS)
456 return (status);
459 * To preserve backward-compatibility, always bring up the link-local
460 * address for implicitly-created IPv6 IPMP interfaces.
462 if (af == AF_INET6)
463 (void) i_ipadm_set_flags(iph, ifname, AF_INET6, IFF_UP, 0);
465 sock = (af == AF_INET ? iph->iph_sock : iph->iph_sock6);
467 * If the caller requested a different group name, issue a
468 * SIOCSLIFGROUPNAME on the new IPMP interface.
470 bzero(&lifr, sizeof (lifr));
471 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
472 if (strcmp(lifr.lifr_name, grname) != 0) {
473 (void) strlcpy(lifr.lifr_groupname, grname, LIFGRNAMSIZ);
474 if (ioctl(sock, SIOCSLIFGROUPNAME, &lifr) == -1) {
475 err = errno;
476 /* Remove the interface we created. */
477 if (status == IPADM_SUCCESS) {
478 (void) i_ipadm_delete_if(iph, ifname, af,
479 ipadm_flags);
481 return (ipadm_errno2status(err));
485 return (IPADM_SUCCESS);
489 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address
490 * family. If so, create a matching IPMP group for address family `af'.
492 static ipadm_status_t
493 i_ipadm_create_ipmp_peer(ipadm_handle_t iph, char *ifname, sa_family_t af)
495 lifgroupinfo_t lifgr;
496 ipadm_status_t status = IPADM_SUCCESS;
497 struct lifreq lifr;
498 int other_af_sock;
500 assert(af == AF_INET || af == AF_INET6);
502 other_af_sock = (af == AF_INET ? iph->iph_sock6 : iph->iph_sock);
505 * iph is the handle for the interface that we are trying to plumb.
506 * other_af_sock is the socket for the "other" address family.
508 bzero(&lifr, sizeof (lifr));
509 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
510 if (ioctl(other_af_sock, SIOCGLIFGROUPNAME, &lifr) != 0)
511 return (IPADM_SUCCESS);
513 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname, LIFGRNAMSIZ);
514 if (ioctl(other_af_sock, SIOCGLIFGROUPINFO, &lifgr) != 0)
515 return (IPADM_SUCCESS);
518 * If `ifname' *is* the IPMP group interface, or if the relevant
519 * address family is already configured, then there's nothing to do.
521 if (strcmp(lifgr.gi_grifname, ifname) == 0 ||
522 (af == AF_INET && lifgr.gi_v4) || (af == AF_INET6 && lifgr.gi_v6)) {
523 return (IPADM_SUCCESS);
526 status = i_ipadm_create_ipmp(iph, lifgr.gi_grifname, af,
527 lifgr.gi_grname, IPADM_OPT_ACTIVE|IPADM_OPT_IPMP);
528 return (status);
532 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd.
534 static ipadm_status_t
535 i_ipadm_slifname_arp(char *ifname, uint64_t flags, int fd)
537 struct lifreq lifr;
538 ifspec_t ifsp;
540 bzero(&lifr, sizeof (lifr));
541 (void) ifparse_ifspec(ifname, &ifsp);
542 lifr.lifr_ppa = ifsp.ifsp_ppa;
543 lifr.lifr_flags = flags;
544 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
546 * Tell ARP the name and unit number for this interface.
547 * Note that arp has no support for transparent ioctls.
549 if (i_ipadm_strioctl(fd, SIOCSLIFNAME, (char *)&lifr,
550 sizeof (lifr)) == -1) {
551 return (ipadm_errno2status(errno));
553 return (IPADM_SUCCESS);
557 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in
558 * `ipadm_flags', then a ppa will be generated. `newif' will be updated
559 * with the generated ppa.
561 static ipadm_status_t
562 i_ipadm_slifname(ipadm_handle_t iph, char *ifname, char *newif, uint64_t flags,
563 int fd, uint32_t ipadm_flags)
565 struct lifreq lifr;
566 ipadm_status_t status = IPADM_SUCCESS;
567 int err = 0;
568 sa_family_t af;
569 int ppa;
570 ifspec_t ifsp;
571 boolean_t valid_if;
573 bzero(&lifr, sizeof (lifr));
574 if (ipadm_flags & IPADM_OPT_GENPPA) {
576 * We'd like to just set lifr_ppa to UINT_MAX and have the
577 * kernel pick a PPA. Unfortunately, that would mishandle
578 * two cases:
580 * 1. If the PPA is available but the groupname is taken
581 * (e.g., the "ipmp2" IP interface name is available
582 * but the "ipmp2" groupname is taken) then the
583 * auto-assignment by the kernel will fail.
585 * 2. If we're creating (e.g.) an IPv6-only IPMP
586 * interface, and there's already an IPv4-only IPMP
587 * interface, the kernel will allow us to accidentally
588 * reuse the IPv6 IPMP interface name (since
589 * SIOCSLIFNAME uniqueness is per-interface-type).
590 * This will cause administrative confusion.
592 * Thus, we instead take a brute-force approach of checking
593 * whether the IPv4 or IPv6 name is already in-use before
594 * attempting the SIOCSLIFNAME. As per (1) above, the
595 * SIOCSLIFNAME may still fail, in which case we just proceed
596 * to the next one. If this approach becomes too slow, we
597 * can add a new SIOC* to handle this case in the kernel.
599 for (ppa = 0; ppa < UINT_MAX; ppa++) {
600 (void) snprintf(lifr.lifr_name, LIFNAMSIZ, "%s%d",
601 ifname, ppa);
603 if (ioctl(iph->iph_sock, SIOCGLIFFLAGS, &lifr) != -1 ||
604 errno != ENXIO)
605 continue;
607 if (ioctl(iph->iph_sock6, SIOCGLIFFLAGS, &lifr) != -1 ||
608 errno != ENXIO)
609 continue;
611 lifr.lifr_ppa = ppa;
612 lifr.lifr_flags = flags;
614 err = ioctl(fd, SIOCSLIFNAME, &lifr);
615 if (err != -1 || errno != EEXIST)
616 break;
618 if (err == -1) {
619 status = ipadm_errno2status(errno);
620 } else {
622 * PPA has been successfully established.
623 * Update `newif' with the ppa.
625 assert(newif != NULL);
626 if (snprintf(newif, LIFNAMSIZ, "%s%d", ifname,
627 ppa) >= LIFNAMSIZ)
628 return (IPADM_INVALID_ARG);
630 } else {
631 /* We should have already validated the interface name. */
632 valid_if = ifparse_ifspec(ifname, &ifsp);
633 assert(valid_if);
636 * Before we call SIOCSLIFNAME, ensure that the IPMP group
637 * interface for this address family exists. Otherwise, the
638 * kernel will kick the interface out of the group when we do
639 * the SIOCSLIFNAME.
641 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
642 * If we're now plumbing bge0 for IPv6, but the IPMP group
643 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
644 * will kick bge0 out of group "a", which is undesired.
646 if (flags & IFF_IPV4)
647 af = AF_INET;
648 else
649 af = AF_INET6;
650 status = i_ipadm_create_ipmp_peer(iph, ifname, af);
651 if (status != IPADM_SUCCESS)
652 return (status);
653 lifr.lifr_ppa = ifsp.ifsp_ppa;
654 lifr.lifr_flags = flags;
655 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
656 if (ioctl(fd, SIOCSLIFNAME, &lifr) == -1)
657 status = ipadm_errno2status(errno);
660 return (status);
664 * Plumbs the interface `ifname' for the address family `af'. It also persists
665 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'.
667 ipadm_status_t
668 i_ipadm_plumb_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
669 uint32_t ipadm_flags)
671 int ip_muxid;
672 int mux_fd = -1, ip_fd, arp_fd;
673 char *udp_dev_name;
674 dlpi_handle_t dh_arp = NULL, dh_ip;
675 uint64_t ifflags;
676 struct lifreq lifr;
677 uint_t dlpi_flags;
678 ipadm_status_t status = IPADM_SUCCESS;
679 char *linkname;
680 boolean_t legacy = (iph->iph_flags & IPH_LEGACY);
681 zoneid_t zoneid;
682 char newif[LIFNAMSIZ];
683 char lifname[LIFNAMSIZ];
684 datalink_id_t linkid;
685 int sock;
686 boolean_t islo;
687 boolean_t is_persistent =
688 ((ipadm_flags & IPADM_OPT_PERSIST) != 0);
689 uint32_t dlflags;
690 dladm_status_t dlstatus;
692 if (iph->iph_dlh != NULL) {
693 dlstatus = dladm_name2info(iph->iph_dlh, ifname, &linkid,
694 &dlflags, NULL, NULL);
697 * If we're in the global zone and we're plumbing a datalink, make
698 * sure that the datalink is not assigned to a non-global zone. Note
699 * that the non-global zones don't need this check, because zoneadm
700 * has taken care of this when the zones boot.
702 if (iph->iph_zoneid == GLOBAL_ZONEID && dlstatus == DLADM_STATUS_OK) {
703 zoneid = ALL_ZONES;
704 if (zone_check_datalink(&zoneid, linkid) == 0) {
705 /* interface is in use by a non-global zone. */
706 return (IPADM_IF_INUSE);
710 /* loopback interfaces are just added as logical interface */
711 bzero(&lifr, sizeof (lifr));
712 islo = i_ipadm_is_loopback(ifname);
713 if (islo || i_ipadm_get_lnum(ifname) != 0) {
714 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
715 if (af == AF_INET)
716 sock = iph->iph_sock;
717 else
718 sock = iph->iph_sock6;
719 if (islo && ioctl(sock, SIOCGLIFADDR, (caddr_t)&lifr) >= 0)
720 return (IPADM_IF_EXISTS);
721 if (ioctl(sock, SIOCLIFADDIF, (caddr_t)&lifr) < 0)
722 return (ipadm_errno2status(errno));
725 * By default, kernel configures 127.0.0.1 on the loopback
726 * interface. Replace this with 0.0.0.0 to be consistent
727 * with interface creation on other physical interfaces.
729 if (islo && !legacy) {
730 bzero(&lifr.lifr_addr, sizeof (lifr.lifr_addr));
731 lifr.lifr_addr.ss_family = af;
732 if (ioctl(sock, SIOCSLIFADDR, (caddr_t)&lifr) < 0)
733 return (ipadm_errno2status(errno));
734 if (is_persistent) {
735 status = i_ipadm_persist_if(iph, ifname, af);
736 if (status != IPADM_SUCCESS) {
737 (void) i_ipadm_delete_if(iph, ifname,
738 af, IPADM_OPT_ACTIVE);
742 return (status);
745 dlpi_flags = DLPI_NOATTACH;
748 * If IPADM_OPT_IPMP is specified, then this is a request
749 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply
750 * pass "ipmpstub0" as devname since an admin *could* have a normal
751 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
753 if (ipadm_flags & IPADM_OPT_IPMP) {
754 dlpi_flags |= DLPI_DEVONLY;
755 linkname = "ipmpstub0";
756 } else {
758 * Verify that the user is not creating a persistent
759 * IP interface on a non-persistent data-link.
761 if (!i_ipadm_is_vni(ifname) && dlstatus == DLADM_STATUS_OK &&
762 is_persistent && !(dlflags & DLADM_OPT_PERSIST)) {
763 return (IPADM_TEMPORARY_OBJ);
765 linkname = ifname;
769 * We use DLPI_NOATTACH because the ip module will do the attach
770 * itself for DLPI style-2 devices.
772 if (dlpi_open(linkname, &dh_ip, dlpi_flags) != DLPI_SUCCESS)
773 return (IPADM_DLPI_FAILURE);
774 ip_fd = dlpi_fd(dh_ip);
775 if (ioctl(ip_fd, I_PUSH, IP_MOD_NAME) == -1) {
776 status = ipadm_errno2status(errno);
777 goto done;
781 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications
782 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL.
784 ifflags = 0;
786 /* Set the name string and the IFF_IPV* flag */
787 if (af == AF_INET) {
788 ifflags = IFF_IPV4;
789 } else {
790 ifflags = IFF_IPV6;
792 * With the legacy method, the link-local address should be
793 * configured as part of the interface plumb, using the default
794 * token. If IPH_LEGACY is not specified, we want to set :: as
795 * the address and require the admin to explicitly call
796 * ipadm_create_addr() with the address object type set to
797 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address
798 * as well as the autoconfigured addresses.
800 if (!legacy && !i_ipadm_is_6to4(iph, ifname))
801 ifflags |= IFF_NOLINKLOCAL;
803 (void) strlcpy(newif, ifname, sizeof (newif));
804 status = i_ipadm_slifname(iph, ifname, newif, ifflags, ip_fd,
805 ipadm_flags);
806 if (status != IPADM_SUCCESS)
807 goto done;
809 /* Get the full set of existing flags for this stream */
810 status = i_ipadm_get_flags(iph, newif, af, &ifflags);
811 if (status != IPADM_SUCCESS)
812 goto done;
814 udp_dev_name = (af == AF_INET6 ? UDP6_DEV_NAME : UDP_DEV_NAME);
815 status = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
816 if (status != IPADM_SUCCESS)
817 goto done;
819 /* Check if arp is not needed */
820 if (ifflags & (IFF_NOARP|IFF_IPV6)) {
822 * PLINK the interface stream so that the application can exit
823 * without tearing down the stream.
825 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1)
826 status = ipadm_errno2status(errno);
827 goto done;
831 * This interface does use ARP, so set up a separate stream
832 * from the interface to ARP.
834 * We use DLPI_NOATTACH because the arp module will do the attach
835 * itself for DLPI style-2 devices.
837 if (dlpi_open(linkname, &dh_arp, dlpi_flags) != DLPI_SUCCESS) {
838 status = IPADM_DLPI_FAILURE;
839 goto done;
842 arp_fd = dlpi_fd(dh_arp);
843 if (ioctl(arp_fd, I_PUSH, ARP_MOD_NAME) == -1) {
844 status = ipadm_errno2status(errno);
845 goto done;
848 status = i_ipadm_slifname_arp(newif, ifflags, arp_fd);
849 if (status != IPADM_SUCCESS)
850 goto done;
852 * PLINK the IP and ARP streams so that ifconfig can exit
853 * without tearing down the stream.
855 if ((ip_muxid = ioctl(mux_fd, I_PLINK, ip_fd)) == -1) {
856 status = ipadm_errno2status(errno);
857 goto done;
860 if (ioctl(mux_fd, I_PLINK, arp_fd) < 0) {
861 status = ipadm_errno2status(errno);
862 (void) ioctl(mux_fd, I_PUNLINK, ip_muxid);
865 done:
866 dlpi_close(dh_ip);
867 if (dh_arp != NULL)
868 dlpi_close(dh_arp);
870 if (mux_fd != -1)
871 (void) close(mux_fd);
873 if (status == IPADM_SUCCESS) {
874 /* copy back new ifname */
875 (void) strlcpy(ifname, newif, LIFNAMSIZ);
877 * If it is a 6to4 tunnel, create a default
878 * addrobj name for the default address on the 0'th
879 * logical interface and set IFF_UP in the interface flags.
881 if (i_ipadm_is_6to4(iph, ifname)) {
882 struct ipadm_addrobj_s addr;
884 i_ipadm_init_addr(&addr, ifname, "", IPADM_ADDR_STATIC);
885 addr.ipadm_af = af;
886 status = i_ipadm_lookupadd_addrobj(iph, &addr);
887 if (status != IPADM_SUCCESS)
888 return (status);
889 status = ipadm_add_aobjname(iph, ifname,
890 af, addr.ipadm_aobjname, IPADM_ADDR_STATIC, 0);
891 if (status != IPADM_SUCCESS)
892 return (status);
893 addr.ipadm_lifnum = 0;
894 i_ipadm_addrobj2lifname(&addr, lifname,
895 sizeof (lifname));
896 status = i_ipadm_set_flags(iph, lifname, af,
897 IFF_UP, 0);
898 if (status != IPADM_SUCCESS)
899 return (status);
900 } else {
902 * Prevent static IPv6 addresses from triggering
903 * autoconf. This does not have to be done for
904 * 6to4 tunnel interfaces, since in.ndpd will
905 * not autoconfigure those interfaces.
907 if (af == AF_INET6 && !legacy)
908 (void) i_ipadm_disable_autoconf(newif);
912 * If IPADM_OPT_PERSIST was set in flags, store the
913 * interface in persistent DB.
915 if (is_persistent) {
916 status = i_ipadm_persist_if(iph, newif, af);
917 if (status != IPADM_SUCCESS) {
918 (void) i_ipadm_delete_if(iph, newif, af,
919 IPADM_OPT_ACTIVE);
923 if (status == IPADM_EXISTS)
924 status = IPADM_IF_EXISTS;
925 return (status);
929 * Unplumbs the interface in `ifname' of family `af'.
931 ipadm_status_t
932 i_ipadm_unplumb_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
934 int ip_muxid, arp_muxid;
935 int mux_fd = -1;
936 int muxid_fd = -1;
937 char *udp_dev_name;
938 uint64_t flags;
939 boolean_t changed_arp_muxid = B_FALSE;
940 int save_errno;
941 struct lifreq lifr;
942 ipadm_status_t ret = IPADM_SUCCESS;
943 int sock;
944 lifgroupinfo_t lifgr;
945 ifaddrlistx_t *ifaddrs, *ifaddrp;
946 boolean_t v6 = (af == AF_INET6);
948 /* Just do SIOCLIFREMOVEIF on loopback interfaces */
949 bzero(&lifr, sizeof (lifr));
950 if (i_ipadm_is_loopback(ifname) ||
951 (i_ipadm_get_lnum(ifname) != 0 && (iph->iph_flags & IPH_LEGACY))) {
952 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
953 if (ioctl((af == AF_INET) ? iph->iph_sock : iph->iph_sock6,
954 SIOCLIFREMOVEIF, (caddr_t)&lifr) < 0) {
955 return (ipadm_errno2status(errno));
957 return (IPADM_SUCCESS);
961 * We used /dev/udp or udp6 to set up the mux. So we have to use
962 * the same now for PUNLINK also.
964 if (v6) {
965 udp_dev_name = UDP6_DEV_NAME;
966 sock = iph->iph_sock6;
967 } else {
968 udp_dev_name = UDP_DEV_NAME;
969 sock = iph->iph_sock;
971 if ((muxid_fd = open(udp_dev_name, O_RDWR)) == -1) {
972 ret = ipadm_errno2status(errno);
973 goto done;
975 ret = ipadm_open_arp_on_udp(udp_dev_name, &mux_fd);
976 if (ret != IPADM_SUCCESS)
977 goto done;
978 (void) strlcpy(lifr.lifr_name, ifname, sizeof (lifr.lifr_name));
979 if (ioctl(muxid_fd, SIOCGLIFFLAGS, (caddr_t)&lifr) < 0) {
980 ret = ipadm_errno2status(errno);
981 goto done;
983 flags = lifr.lifr_flags;
984 again:
985 if (flags & IFF_IPMP) {
987 * There are two reasons the I_PUNLINK can fail with EBUSY:
988 * (1) if IP interfaces are in the group, or (2) if IPMP data
989 * addresses are administratively up. For case (1), we fail
990 * here with a specific error message. For case (2), we bring
991 * down the addresses prior to doing the I_PUNLINK. If the
992 * I_PUNLINK still fails with EBUSY then the configuration
993 * must have changed after our checks, in which case we branch
994 * back up to `again' and rerun this logic. The net effect is
995 * that unplumbing an IPMP interface will only fail with EBUSY
996 * if IP interfaces are in the group.
998 if (ioctl(sock, SIOCGLIFGROUPNAME, &lifr) == -1) {
999 ret = ipadm_errno2status(errno);
1000 goto done;
1002 (void) strlcpy(lifgr.gi_grname, lifr.lifr_groupname,
1003 LIFGRNAMSIZ);
1004 if (ioctl(sock, SIOCGLIFGROUPINFO, &lifgr) == -1) {
1005 ret = ipadm_errno2status(errno);
1006 goto done;
1008 if ((v6 && lifgr.gi_nv6 != 0) || (!v6 && lifgr.gi_nv4 != 0)) {
1009 ret = IPADM_GRP_NOTEMPTY;
1010 goto done;
1014 * The kernel will fail the I_PUNLINK if the IPMP interface
1015 * has administratively up addresses; bring them down.
1017 if (ifaddrlistx(ifname, IFF_UP|IFF_DUPLICATE,
1018 0, &ifaddrs) == -1) {
1019 ret = ipadm_errno2status(errno);
1020 goto done;
1022 ifaddrp = ifaddrs;
1023 for (; ifaddrp != NULL; ifaddrp = ifaddrp->ia_next) {
1024 int sock = (ifaddrp->ia_flags & IFF_IPV4) ?
1025 iph->iph_sock : iph->iph_sock6;
1026 struct lifreq lifrl;
1028 if (((ifaddrp->ia_flags & IFF_IPV6) && !v6) ||
1029 (!(ifaddrp->ia_flags & IFF_IPV6) && v6))
1030 continue;
1032 bzero(&lifrl, sizeof (lifrl));
1033 (void) strlcpy(lifrl.lifr_name, ifaddrp->ia_name,
1034 sizeof (lifrl.lifr_name));
1035 if (ioctl(sock, SIOCGLIFFLAGS, &lifrl) < 0) {
1036 ret = ipadm_errno2status(errno);
1037 ifaddrlistx_free(ifaddrs);
1038 goto done;
1040 if (lifrl.lifr_flags & IFF_UP) {
1041 ret = i_ipadm_set_flags(iph, lifrl.lifr_name,
1042 ((lifrl.lifr_flags & IFF_IPV4) ? AF_INET :
1043 AF_INET6), 0, IFF_UP);
1044 if (ret != IPADM_SUCCESS) {
1045 ifaddrlistx_free(ifaddrs);
1046 goto done;
1048 } else if (lifrl.lifr_flags & IFF_DUPLICATE) {
1049 if (ioctl(sock, SIOCGLIFADDR, &lifrl) < 0 ||
1050 ioctl(sock, SIOCSLIFADDR, &lifrl) < 0) {
1051 ret = ipadm_errno2status(errno);
1052 ifaddrlistx_free(ifaddrs);
1053 goto done;
1057 ifaddrlistx_free(ifaddrs);
1060 if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)&lifr) < 0) {
1061 ret = ipadm_errno2status(errno);
1062 goto done;
1064 arp_muxid = lifr.lifr_arp_muxid;
1065 ip_muxid = lifr.lifr_ip_muxid;
1068 * We don't have a good way of knowing whether the arp stream is
1069 * plumbed. We can't rely on IFF_NOARP because someone could
1070 * have turned it off later using "ifconfig xxx -arp".
1072 if (arp_muxid != 0) {
1073 if (ioctl(mux_fd, I_PUNLINK, arp_muxid) < 0) {
1075 * See the comment before the SIOCGLIFGROUPNAME call.
1077 if (errno == EBUSY && (flags & IFF_IPMP))
1078 goto again;
1080 if ((errno == EINVAL) &&
1081 (flags & (IFF_NOARP | IFF_IPV6))) {
1083 * Some plumbing utilities set the muxid to
1084 * -1 or some invalid value to signify that
1085 * there is no arp stream. Set the muxid to 0
1086 * before trying to unplumb the IP stream.
1087 * IP does not allow the IP stream to be
1088 * unplumbed if it sees a non-null arp muxid,
1089 * for consistency of IP-ARP streams.
1091 lifr.lifr_arp_muxid = 0;
1092 (void) ioctl(muxid_fd, SIOCSLIFMUXID,
1093 (caddr_t)&lifr);
1094 changed_arp_muxid = B_TRUE;
1097 * In case of any other error, we continue with
1098 * the unplumb.
1103 if (ioctl(mux_fd, I_PUNLINK, ip_muxid) < 0) {
1104 if (changed_arp_muxid) {
1106 * Some error occurred, and we need to restore
1107 * everything back to what it was.
1109 save_errno = errno;
1110 lifr.lifr_arp_muxid = arp_muxid;
1111 lifr.lifr_ip_muxid = ip_muxid;
1112 (void) ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)&lifr);
1113 errno = save_errno;
1116 * See the comment before the SIOCGLIFGROUPNAME call.
1118 if (errno == EBUSY && (flags & IFF_IPMP))
1119 goto again;
1121 ret = ipadm_errno2status(errno);
1123 done:
1124 if (muxid_fd != -1)
1125 (void) close(muxid_fd);
1126 if (mux_fd != -1)
1127 (void) close(mux_fd);
1129 if (af == AF_INET6 && ret == IPADM_SUCCESS) {
1131 * in.ndpd maintains the phyints in its memory even after
1132 * the interface is plumbed, so that it can be reused when
1133 * the interface gets plumbed again. The default behavior
1134 * of in.ndpd is to start autoconfiguration for an interface
1135 * that gets plumbed. We need to send the
1136 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1137 * default behavior on replumb.
1139 (void) i_ipadm_enable_autoconf(ifname);
1141 return (ret);
1145 * Saves the given interface name `ifname' with address family `af' in
1146 * persistent DB.
1148 static ipadm_status_t
1149 i_ipadm_persist_if(ipadm_handle_t iph, const char *ifname, sa_family_t af)
1151 ipmgmt_if_arg_t ifarg;
1152 int err;
1154 (void) strlcpy(ifarg.ia_ifname, ifname, sizeof (ifarg.ia_ifname));
1155 ifarg.ia_family = af;
1156 ifarg.ia_cmd = IPMGMT_CMD_SETIF;
1157 ifarg.ia_flags = IPMGMT_PERSIST;
1158 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1159 return (ipadm_errno2status(err));
1163 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1164 * is set in `ipadm_flags', it is also removed from persistent configuration.
1166 ipadm_status_t
1167 i_ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1168 uint32_t ipadm_flags)
1170 ipadm_status_t ret = IPADM_SUCCESS;
1171 ipadm_status_t db_status;
1172 char tmp_ifname[LIFNAMSIZ];
1173 char *cp;
1174 struct ipadm_addrobj_s ipaddr;
1175 boolean_t is_persistent =
1176 (ipadm_flags & IPADM_OPT_PERSIST);
1178 ret = i_ipadm_unplumb_if(iph, ifname, af);
1179 if (ret != IPADM_SUCCESS)
1180 goto done;
1182 cp = strrchr(ifname, IPADM_LOGICAL_SEP);
1183 if (cp != NULL) {
1184 assert(iph->iph_flags & IPH_LEGACY);
1186 * This is a non-zero logical interface.
1187 * Find the addrobj and remove it from the daemon's memory.
1189 (void) strlcpy(tmp_ifname, ifname, sizeof (tmp_ifname));
1190 tmp_ifname[cp - ifname] = '\0';
1191 *cp++ = '\0';
1192 ipaddr.ipadm_lifnum = atoi(cp);
1193 (void) strlcpy(ipaddr.ipadm_ifname, tmp_ifname,
1194 sizeof (ipaddr.ipadm_ifname));
1195 ipaddr.ipadm_af = af;
1196 ret = i_ipadm_get_lif2addrobj(iph, &ipaddr);
1197 if (ret == IPADM_SUCCESS) {
1198 ret = i_ipadm_delete_addrobj(iph, &ipaddr,
1199 IPADM_OPT_ACTIVE);
1200 } else if (ret == IPADM_NOTFOUND) {
1201 ret = IPADM_SUCCESS;
1203 return (ret);
1205 done:
1207 * Even if interface does not exist, remove all its addresses and
1208 * properties from the persistent store. If interface does not
1209 * exist both in kernel and the persistent store, return IPADM_ENXIO.
1211 if ((ret == IPADM_ENXIO && is_persistent) || ret == IPADM_SUCCESS) {
1212 db_status = i_ipadm_delete_ifobj(iph, ifname, af,
1213 is_persistent);
1214 if (db_status == IPADM_SUCCESS)
1215 ret = IPADM_SUCCESS;
1218 return (ret);
1222 * Resets all addresses on interface `ifname' with address family `af'
1223 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties
1224 * and address objects of `ifname' for `af' are also removed from the
1225 * persistent DB.
1227 ipadm_status_t
1228 i_ipadm_delete_ifobj(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1229 boolean_t is_persistent)
1231 ipmgmt_if_arg_t ifarg;
1232 int err;
1234 ifarg.ia_cmd = IPMGMT_CMD_RESETIF;
1235 ifarg.ia_flags = IPMGMT_ACTIVE;
1236 if (is_persistent)
1237 ifarg.ia_flags |= IPMGMT_PERSIST;
1238 ifarg.ia_family = af;
1239 (void) strlcpy(ifarg.ia_ifname, ifname, LIFNAMSIZ);
1241 err = ipadm_door_call(iph, &ifarg, sizeof (ifarg), NULL, 0, B_FALSE);
1242 return (ipadm_errno2status(err));
1246 * Create the interface by plumbing it for IP.
1247 * This function will check if there is saved configuration information
1248 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1249 * for `ifname' is taken.
1251 ipadm_status_t
1252 i_ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1253 uint32_t ipadm_flags)
1255 ipadm_status_t status;
1256 boolean_t p_exists;
1257 sa_family_t other_af;
1260 * Return error, if the interface already exists in either the active
1261 * or the persistent configuration.
1263 if (ipadm_if_enabled(iph, ifname, af))
1264 return (IPADM_IF_EXISTS);
1266 if (!(iph->iph_flags & IPH_LEGACY)) {
1267 status = i_ipadm_if_pexists(iph, ifname, af, &p_exists);
1268 if (status != IPADM_SUCCESS)
1269 return (status);
1270 other_af = (af == AF_INET ? AF_INET6 : AF_INET);
1271 if (p_exists) {
1272 if (!ipadm_if_enabled(iph, ifname, other_af))
1273 return (IPADM_OP_DISABLE_OBJ);
1274 else
1275 ipadm_flags &= ~IPADM_OPT_PERSIST;
1279 return (i_ipadm_plumb_if(iph, ifname, af, ipadm_flags));
1283 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1284 * default, unless a value in `af' is specified. The interface may be plumbed
1285 * only if there is no previously saved persistent configuration information
1286 * for the interface (in which case the ipadm_enable_if() function must
1287 * be used to enable the interface).
1289 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1290 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1291 * or appropriate ipadm_status_t corresponding to the errno.
1293 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1294 * be over-written with the actual interface name when a PPA has to be
1295 * internally generated by the library.
1297 ipadm_status_t
1298 ipadm_create_if(ipadm_handle_t iph, char *ifname, sa_family_t af,
1299 uint32_t flags)
1301 ipadm_status_t status;
1302 boolean_t created_v4 = B_FALSE;
1303 char newifname[LIFNAMSIZ];
1305 /* Check for the required authorization */
1306 if (!ipadm_check_auth())
1307 return (IPADM_EAUTH);
1309 if (flags == 0 || ((flags & IPADM_OPT_PERSIST) &&
1310 !(flags & IPADM_OPT_ACTIVE)) ||
1311 (flags & ~(IPADM_COMMON_OPT_MASK | IPADM_OPT_IPMP |
1312 IPADM_OPT_GENPPA))) {
1313 return (IPADM_INVALID_ARG);
1315 if (flags & IPADM_OPT_GENPPA) {
1316 if (snprintf(newifname, LIFNAMSIZ, "%s0", ifname) >=
1317 LIFNAMSIZ)
1318 return (IPADM_INVALID_ARG);
1319 } else {
1320 if (strlcpy(newifname, ifname, LIFNAMSIZ) >= LIFNAMSIZ)
1321 return (IPADM_INVALID_ARG);
1324 if (!i_ipadm_validate_ifname(iph, newifname))
1325 return (IPADM_INVALID_ARG);
1327 if ((af == AF_INET || af == AF_UNSPEC) &&
1328 !i_ipadm_is_6to4(iph, ifname)) {
1329 status = i_ipadm_create_if(iph, ifname, AF_INET, flags);
1330 if (status != IPADM_SUCCESS)
1331 return (status);
1332 created_v4 = B_TRUE;
1334 if (af == AF_INET6 || af == AF_UNSPEC) {
1335 status = i_ipadm_create_if(iph, ifname, AF_INET6, flags);
1336 if (status != IPADM_SUCCESS) {
1337 if (created_v4) {
1338 (void) i_ipadm_delete_if(iph, ifname, AF_INET,
1339 IPADM_OPT_ACTIVE);
1341 return (status);
1345 return (IPADM_SUCCESS);
1349 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1350 * when `af' = AF_UNSPEC.
1352 ipadm_status_t
1353 ipadm_delete_if(ipadm_handle_t iph, const char *ifname, sa_family_t af,
1354 uint32_t flags)
1356 ipadm_status_t status1 = IPADM_SUCCESS;
1357 ipadm_status_t status2 = IPADM_SUCCESS;
1358 ipadm_status_t other;
1360 /* Check for the required authorization */
1361 if (!ipadm_check_auth())
1362 return (IPADM_EAUTH);
1364 /* Validate the `ifname' for any logical interface. */
1365 if (flags == 0 || (flags & ~(IPADM_COMMON_OPT_MASK)) ||
1366 !i_ipadm_validate_ifname(iph, ifname))
1367 return (IPADM_INVALID_ARG);
1369 if (af == AF_INET || af == AF_UNSPEC)
1370 status1 = i_ipadm_delete_if(iph, ifname, AF_INET, flags);
1371 if (af == AF_INET6 || af == AF_UNSPEC)
1372 status2 = i_ipadm_delete_if(iph, ifname, AF_INET6, flags);
1374 * If the family has been uniquely identified, we return the
1375 * associated status, even if that is ENXIO. Calls from ifconfig
1376 * which can only unplumb one of IPv4/IPv6 at any time fall under
1377 * this category.
1379 if (af == AF_INET)
1380 return (status1);
1381 else if (af == AF_INET6)
1382 return (status2);
1383 else if (af != AF_UNSPEC)
1384 return (IPADM_INVALID_ARG);
1387 * If af is AF_UNSPEC, then we return the following:
1388 * status1, if status1 == status2
1389 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS
1390 * and the other status is ENXIO
1391 * IPADM_ENXIO, if both status1 and status2 are ENXIO
1392 * IPADM_FAILURE otherwise.
1394 if (status1 == status2) {
1395 /* covers the case when both status1 and status2 are ENXIO */
1396 return (status1);
1397 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1398 if (status1 == IPADM_SUCCESS)
1399 other = status2;
1400 else
1401 other = status1;
1402 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1403 } else {
1404 return (IPADM_FAILURE);
1409 * Returns information about all interfaces in both active and persistent
1410 * configuration. If `ifname' is not NULL, it returns only the interface
1411 * identified by `ifname'.
1413 * Return values:
1414 * On success: IPADM_SUCCESS.
1415 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE.
1417 ipadm_status_t
1418 ipadm_if_info(ipadm_handle_t iph, const char *ifname,
1419 ipadm_if_info_t **if_info, uint32_t flags, int64_t lifc_flags)
1421 ipadm_status_t status;
1422 ifspec_t ifsp;
1424 if (if_info == NULL || iph == NULL || flags != 0)
1425 return (IPADM_INVALID_ARG);
1427 if (ifname != NULL &&
1428 (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)) {
1429 return (IPADM_INVALID_ARG);
1432 status = i_ipadm_get_all_if_info(iph, ifname, if_info, lifc_flags);
1433 if (status != IPADM_SUCCESS)
1434 return (status);
1435 if (ifname != NULL && *if_info == NULL)
1436 return (IPADM_ENXIO);
1438 return (IPADM_SUCCESS);
1442 * Frees the linked list allocated by ipadm_if_info().
1444 void
1445 ipadm_free_if_info(ipadm_if_info_t *ifinfo)
1447 ipadm_if_info_t *ifinfo_next;
1449 for (; ifinfo != NULL; ifinfo = ifinfo_next) {
1450 ifinfo_next = ifinfo->ifi_next;
1451 free(ifinfo);
1456 * Re-enable the interface `ifname' based on the saved configuration
1457 * for `ifname'.
1459 ipadm_status_t
1460 ipadm_enable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1462 nvlist_t *ifnvl;
1463 ipadm_status_t status;
1464 ifspec_t ifsp;
1466 /* Check for the required authorization */
1467 if (!ipadm_check_auth())
1468 return (IPADM_EAUTH);
1470 /* Check for logical interfaces. */
1471 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1472 return (IPADM_INVALID_ARG);
1474 /* Enabling an interface persistently is not supported. */
1475 if (flags & IPADM_OPT_PERSIST)
1476 return (IPADM_NOTSUP);
1479 * Return early by checking if the interface is already enabled.
1481 if (ipadm_if_enabled(iph, ifname, AF_INET) &&
1482 ipadm_if_enabled(iph, ifname, AF_INET6)) {
1483 return (IPADM_IF_EXISTS);
1486 * Enable the interface and restore all its interface properties
1487 * and address objects.
1489 status = i_ipadm_init_ifs(iph, ifname, &ifnvl);
1490 if (status != IPADM_SUCCESS)
1491 return (status);
1493 assert(ifnvl != NULL);
1495 * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
1496 * but only for one interface. We need to set IPH_INIT because
1497 * ipmgmtd daemon does not have to write the interface to persistent
1498 * db. The interface is already available in persistent db
1499 * and we are here to re-enable the persistent configuration.
1501 iph->iph_flags |= IPH_INIT;
1502 status = i_ipadm_init_ifobj(iph, ifname, ifnvl);
1503 iph->iph_flags &= ~IPH_INIT;
1505 nvlist_free(ifnvl);
1506 return (status);
1510 * Disable the interface `ifname' by removing it from the active configuration.
1511 * Error code return values follow the model in ipadm_delete_if()
1513 ipadm_status_t
1514 ipadm_disable_if(ipadm_handle_t iph, const char *ifname, uint32_t flags)
1516 ipadm_status_t status1, status2, other;
1517 ifspec_t ifsp;
1519 /* Check for the required authorization */
1520 if (!ipadm_check_auth())
1521 return (IPADM_EAUTH);
1523 /* Check for logical interfaces. */
1524 if (!ifparse_ifspec(ifname, &ifsp) || ifsp.ifsp_lunvalid)
1525 return (IPADM_INVALID_ARG);
1527 /* Disabling an interface persistently is not supported. */
1528 if (flags & IPADM_OPT_PERSIST)
1529 return (IPADM_NOTSUP);
1531 status1 = i_ipadm_unplumb_if(iph, ifname, AF_INET6);
1532 if (status1 == IPADM_SUCCESS)
1533 status1 = i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);
1534 status2 = i_ipadm_unplumb_if(iph, ifname, AF_INET);
1535 if (status2 == IPADM_SUCCESS)
1536 status2 = i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1537 if (status1 == status2) {
1538 return (status2);
1539 } else if (status1 == IPADM_SUCCESS || status2 == IPADM_SUCCESS) {
1540 if (status1 == IPADM_SUCCESS)
1541 other = status2;
1542 else
1543 other = status1;
1544 return (other == IPADM_ENXIO ? IPADM_SUCCESS : IPADM_FAILURE);
1545 } else {
1546 return (IPADM_FAILURE);
1551 * This workaround is until libipadm supports IPMP and is required whenever an
1552 * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1553 * yet, we will have to update the daemon's in-memory mapping of
1554 * `aobjname' to 'lifnum'.
1556 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1557 * door_call(3C) fails. Also, there is no use in returning error because
1558 * `ifname' would have been successfuly moved into IPMP group, by this time.
1560 void
1561 ipadm_if_move(ipadm_handle_t iph, const char *ifname)
1563 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET, B_FALSE);
1564 (void) i_ipadm_delete_ifobj(iph, ifname, AF_INET6, B_FALSE);