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]
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/sockio.h>
33 #include <libdllink.h>
34 #include <libinetutil.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 *,
46 static ipadm_status_t
i_ipadm_persist_if(ipadm_handle_t
, const char *,
50 * Returns B_FALSE if the interface in `ifname' has at least one address that is
51 * IFF_UP in the addresses in `ifa'.
54 i_ipadm_is_if_down(char *ifname
, struct ifaddrs
*ifa
)
57 char cifname
[LIFNAMSIZ
];
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
)
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
)) {
73 /* We did not find any IFF_UP addresses. */
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'.
84 i_ipadm_active_if_info(ipadm_handle_t iph
, const char *ifname
,
85 ipadm_if_info_t
**if_info
, int64_t lifc_flags
)
90 ipadm_if_info_t
*last
= NULL
;
95 ipadm_status_t status
;
99 * Get information for all interfaces.
101 if (getallifs(iph
->iph_sock
, 0, &buf
, &numifs
, lifc_flags
) != 0)
102 return (ipadm_errno2status(errno
));
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)
110 * Skip the current interface if a specific `ifname' has
111 * been requested and current interface does not match
114 if (ifname
!= NULL
&& strcmp(lifrp
->lifr_name
, ifname
) != 0)
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)
125 ifp
= calloc(1, sizeof (ipadm_if_info_t
));
127 status
= ipadm_errno2status(errno
);
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
)
136 last
->ifi_next
= 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)
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
;
176 return (IPADM_SUCCESS
);
179 ipadm_free_if_info(*if_info
);
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
;
199 bzero(&getif
, sizeof (getif
));
201 (void) strlcpy(getif
.ia_ifname
, ifname
, LIFNAMSIZ
);
202 getif
.ia_cmd
= IPMGMT_CMD_GETIF
;
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
);
213 return (ipadm_errno2status(err
));
214 return (IPADM_SUCCESS
);
215 } else if (err
!= 0) {
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
);
228 (void) bcopy(ifp
, curr
, sizeof (*curr
));
229 curr
->ifi_next
= prev
;
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
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
;
254 struct ifaddrs
*ifap
;
257 * Retrive the information for the requested `ifname' or all
258 * interfaces from active configuration.
261 status
= i_ipadm_active_if_info(iph
, ifname
, &aifinfo
, lifc_flags
);
262 if (status
!= IPADM_SUCCESS
)
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
);
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 (ifap
->ifa_addr
->sa_family
== AF_LINK
)
281 if (strcmp(ifap
->ifa_name
, aifp
->ifi_name
) == 0)
286 * The interface might have been removed
287 * from kernel. Retry getting all the active
291 ipadm_free_if_info(aifinfo
);
295 if (!(ifap
->ifa_flags
& IFF_RUNNING
) ||
296 (ifap
->ifa_flags
& IFF_FAILED
))
297 aifp
->ifi_state
= IFIS_FAILED
;
298 else if (ifap
->ifa_flags
& IFF_OFFLINE
)
299 aifp
->ifi_state
= IFIS_OFFLINE
;
300 else if (i_ipadm_is_if_down(aifp
->ifi_name
, ifa
))
301 aifp
->ifi_state
= IFIS_DOWN
;
303 aifp
->ifi_state
= IFIS_OK
;
304 if (aifp
->ifi_next
== NULL
)
310 * Get the persistent interface information in `pifinfo'.
312 status
= i_ipadm_persist_if_info(iph
, ifname
, &pifinfo
);
313 if (status
== IPADM_NOTFOUND
) {
315 return (IPADM_SUCCESS
);
317 if (status
!= IPADM_SUCCESS
)
320 * If a persistent interface is also found in `aifinfo', update
321 * its entry in `aifinfo' with the persistent information from
322 * `pifinfo'. If an interface is found in `pifinfo', but not in
323 * `aifinfo', it means that this interface was disabled. We should
324 * add this interface to `aifinfo' and set it state to IFIF_DISABLED.
326 for (pifp
= pifinfo
; pifp
!= NULL
; pifp
= pifp
->ifi_next
) {
327 for (aifp
= aifinfo
; aifp
!= NULL
; aifp
= aifp
->ifi_next
) {
328 if (strcmp(aifp
->ifi_name
, pifp
->ifi_name
) == 0) {
329 aifp
->ifi_pflags
= pifp
->ifi_pflags
;
334 aifp
= malloc(sizeof (ipadm_if_info_t
));
336 status
= ipadm_errno2status(errno
);
340 aifp
->ifi_next
= NULL
;
341 aifp
->ifi_state
= IFIS_DISABLED
;
343 last
->ifi_next
= aifp
;
350 ipadm_free_if_info(pifinfo
);
351 return (IPADM_SUCCESS
);
354 ipadm_free_if_info(aifinfo
);
355 ipadm_free_if_info(pifinfo
);
360 i_ipadm_get_lnum(const char *ifname
)
362 char *num
= strrchr(ifname
, IPADM_LOGICAL_SEP
);
367 return (atoi(++num
));
371 * Sets the output argument `exists' to true or false based on whether
372 * any persistent configuration is available for `ifname' and returns
373 * IPADM_SUCCESS as status. If the persistent information cannot be retrieved,
374 * `exists' is unmodified and an error status is returned.
377 i_ipadm_if_pexists(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
380 ipadm_if_info_t
*ifinfo
;
381 ipadm_status_t status
;
384 * if IPH_IPMGMTD is set, we know that the caller (ipmgmtd) already
385 * knows about persistent configuration in the first place, so we
386 * just return success.
388 if (iph
->iph_flags
& IPH_IPMGMTD
) {
390 return (IPADM_SUCCESS
);
392 status
= i_ipadm_persist_if_info(iph
, ifname
, &ifinfo
);
393 if (status
== IPADM_SUCCESS
) {
394 *exists
= ((af
== AF_INET
&&
395 (ifinfo
->ifi_pflags
& IFIF_IPV4
)) ||
397 (ifinfo
->ifi_pflags
& IFIF_IPV6
)));
399 } else if (status
== IPADM_NOTFOUND
) {
400 status
= IPADM_SUCCESS
;
407 * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream
408 * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let
409 * you PLINK a driver under itself, and "/dev/ip" is typically the driver at
410 * the bottom of the stream for tunneling interfaces.
413 ipadm_open_arp_on_udp(const char *udp_dev_name
, int *fd
)
417 if ((*fd
= open(udp_dev_name
, O_RDWR
)) == -1)
418 return (ipadm_errno2status(errno
));
421 * Pop off all undesired modules (note that the user may have
422 * configured autopush to add modules above udp), and push the
423 * arp module onto the resulting stream. This is used to make
424 * IP+ARP be able to atomically track the muxid for the I_PLINKed
425 * STREAMS, thus it isn't related to ARP running the ARP protocol.
427 while (ioctl(*fd
, I_POP
, 0) != -1)
429 if (errno
== EINVAL
&& ioctl(*fd
, I_PUSH
, ARP_MOD_NAME
) != -1)
430 return (IPADM_SUCCESS
);
434 return (ipadm_errno2status(err
));
438 * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an
439 * underlying interface in an ipmp group G is plumbed for an address family,
440 * but the meta-interface for the other address family `af' does not exist
441 * yet for the group G. If `af' is IPv6, we need to bring up the
442 * link-local address.
444 static ipadm_status_t
445 i_ipadm_create_ipmp(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
446 const char *grname
, uint32_t ipadm_flags
)
448 ipadm_status_t status
;
453 assert(ipadm_flags
& IPADM_OPT_IPMP
);
455 /* Create the ipmp underlying interface */
456 status
= i_ipadm_create_if(iph
, ifname
, af
, ipadm_flags
);
457 if (status
!= IPADM_SUCCESS
&& status
!= IPADM_IF_EXISTS
)
461 * To preserve backward-compatibility, always bring up the link-local
462 * address for implicitly-created IPv6 IPMP interfaces.
465 (void) i_ipadm_set_flags(iph
, ifname
, AF_INET6
, IFF_UP
, 0);
467 sock
= (af
== AF_INET
? iph
->iph_sock
: iph
->iph_sock6
);
469 * If the caller requested a different group name, issue a
470 * SIOCSLIFGROUPNAME on the new IPMP interface.
472 bzero(&lifr
, sizeof (lifr
));
473 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
474 if (strcmp(lifr
.lifr_name
, grname
) != 0) {
475 (void) strlcpy(lifr
.lifr_groupname
, grname
, LIFGRNAMSIZ
);
476 if (ioctl(sock
, SIOCSLIFGROUPNAME
, &lifr
) == -1) {
478 /* Remove the interface we created. */
479 if (status
== IPADM_SUCCESS
) {
480 (void) i_ipadm_delete_if(iph
, ifname
, af
,
483 return (ipadm_errno2status(err
));
487 return (IPADM_SUCCESS
);
491 * Checks if `ifname' is plumbed and in an IPMP group on its "other" address
492 * family. If so, create a matching IPMP group for address family `af'.
494 static ipadm_status_t
495 i_ipadm_create_ipmp_peer(ipadm_handle_t iph
, char *ifname
, sa_family_t af
)
497 lifgroupinfo_t lifgr
;
498 ipadm_status_t status
= IPADM_SUCCESS
;
502 assert(af
== AF_INET
|| af
== AF_INET6
);
504 other_af_sock
= (af
== AF_INET
? iph
->iph_sock6
: iph
->iph_sock
);
507 * iph is the handle for the interface that we are trying to plumb.
508 * other_af_sock is the socket for the "other" address family.
510 bzero(&lifr
, sizeof (lifr
));
511 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
512 if (ioctl(other_af_sock
, SIOCGLIFGROUPNAME
, &lifr
) != 0)
513 return (IPADM_SUCCESS
);
515 (void) strlcpy(lifgr
.gi_grname
, lifr
.lifr_groupname
, LIFGRNAMSIZ
);
516 if (ioctl(other_af_sock
, SIOCGLIFGROUPINFO
, &lifgr
) != 0)
517 return (IPADM_SUCCESS
);
520 * If `ifname' *is* the IPMP group interface, or if the relevant
521 * address family is already configured, then there's nothing to do.
523 if (strcmp(lifgr
.gi_grifname
, ifname
) == 0 ||
524 (af
== AF_INET
&& lifgr
.gi_v4
) || (af
== AF_INET6
&& lifgr
.gi_v6
)) {
525 return (IPADM_SUCCESS
);
528 status
= i_ipadm_create_ipmp(iph
, lifgr
.gi_grifname
, af
,
529 lifgr
.gi_grname
, IPADM_OPT_ACTIVE
|IPADM_OPT_IPMP
);
534 * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd.
536 static ipadm_status_t
537 i_ipadm_slifname_arp(char *ifname
, uint64_t flags
, int fd
)
542 bzero(&lifr
, sizeof (lifr
));
543 (void) ifparse_ifspec(ifname
, &ifsp
);
544 lifr
.lifr_ppa
= ifsp
.ifsp_ppa
;
545 lifr
.lifr_flags
= flags
;
546 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
548 * Tell ARP the name and unit number for this interface.
549 * Note that arp has no support for transparent ioctls.
551 if (i_ipadm_strioctl(fd
, SIOCSLIFNAME
, (char *)&lifr
,
552 sizeof (lifr
)) == -1) {
553 return (ipadm_errno2status(errno
));
555 return (IPADM_SUCCESS
);
559 * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in
560 * `ipadm_flags', then a ppa will be generated. `newif' will be updated
561 * with the generated ppa.
563 static ipadm_status_t
564 i_ipadm_slifname(ipadm_handle_t iph
, char *ifname
, char *newif
, uint64_t flags
,
565 int fd
, uint32_t ipadm_flags
)
568 ipadm_status_t status
= IPADM_SUCCESS
;
575 bzero(&lifr
, sizeof (lifr
));
576 if (ipadm_flags
& IPADM_OPT_GENPPA
) {
578 * We'd like to just set lifr_ppa to UINT_MAX and have the
579 * kernel pick a PPA. Unfortunately, that would mishandle
582 * 1. If the PPA is available but the groupname is taken
583 * (e.g., the "ipmp2" IP interface name is available
584 * but the "ipmp2" groupname is taken) then the
585 * auto-assignment by the kernel will fail.
587 * 2. If we're creating (e.g.) an IPv6-only IPMP
588 * interface, and there's already an IPv4-only IPMP
589 * interface, the kernel will allow us to accidentally
590 * reuse the IPv6 IPMP interface name (since
591 * SIOCSLIFNAME uniqueness is per-interface-type).
592 * This will cause administrative confusion.
594 * Thus, we instead take a brute-force approach of checking
595 * whether the IPv4 or IPv6 name is already in-use before
596 * attempting the SIOCSLIFNAME. As per (1) above, the
597 * SIOCSLIFNAME may still fail, in which case we just proceed
598 * to the next one. If this approach becomes too slow, we
599 * can add a new SIOC* to handle this case in the kernel.
601 for (ppa
= 0; ppa
< UINT_MAX
; ppa
++) {
602 (void) snprintf(lifr
.lifr_name
, LIFNAMSIZ
, "%s%d",
605 if (ioctl(iph
->iph_sock
, SIOCGLIFFLAGS
, &lifr
) != -1 ||
609 if (ioctl(iph
->iph_sock6
, SIOCGLIFFLAGS
, &lifr
) != -1 ||
614 lifr
.lifr_flags
= flags
;
616 err
= ioctl(fd
, SIOCSLIFNAME
, &lifr
);
617 if (err
!= -1 || errno
!= EEXIST
)
621 status
= ipadm_errno2status(errno
);
624 * PPA has been successfully established.
625 * Update `newif' with the ppa.
627 assert(newif
!= NULL
);
628 if (snprintf(newif
, LIFNAMSIZ
, "%s%d", ifname
,
630 return (IPADM_INVALID_ARG
);
633 /* We should have already validated the interface name. */
634 valid_if
= ifparse_ifspec(ifname
, &ifsp
);
638 * Before we call SIOCSLIFNAME, ensure that the IPMP group
639 * interface for this address family exists. Otherwise, the
640 * kernel will kick the interface out of the group when we do
643 * Example: suppose bge0 is plumbed for IPv4 and in group "a".
644 * If we're now plumbing bge0 for IPv6, but the IPMP group
645 * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME
646 * will kick bge0 out of group "a", which is undesired.
648 if (flags
& IFF_IPV4
)
652 status
= i_ipadm_create_ipmp_peer(iph
, ifname
, af
);
653 if (status
!= IPADM_SUCCESS
)
655 lifr
.lifr_ppa
= ifsp
.ifsp_ppa
;
656 lifr
.lifr_flags
= flags
;
657 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
658 if (ioctl(fd
, SIOCSLIFNAME
, &lifr
) == -1)
659 status
= ipadm_errno2status(errno
);
666 * Plumbs the interface `ifname' for the address family `af'. It also persists
667 * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'.
670 i_ipadm_plumb_if(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
671 uint32_t ipadm_flags
)
674 int mux_fd
= -1, ip_fd
, arp_fd
;
676 dlpi_handle_t dh_arp
= NULL
, dh_ip
;
680 ipadm_status_t status
= IPADM_SUCCESS
;
682 boolean_t legacy
= (iph
->iph_flags
& IPH_LEGACY
);
684 char newif
[LIFNAMSIZ
];
685 char lifname
[LIFNAMSIZ
];
686 datalink_id_t linkid
;
689 boolean_t is_persistent
=
690 ((ipadm_flags
& IPADM_OPT_PERSIST
) != 0);
692 dladm_status_t dlstatus
;
694 if (iph
->iph_dlh
!= NULL
) {
695 dlstatus
= dladm_name2info(iph
->iph_dlh
, ifname
, &linkid
,
696 &dlflags
, NULL
, NULL
);
699 * If we're in the global zone and we're plumbing a datalink, make
700 * sure that the datalink is not assigned to a non-global zone. Note
701 * that the non-global zones don't need this check, because zoneadm
702 * has taken care of this when the zones boot.
704 if (iph
->iph_zoneid
== GLOBAL_ZONEID
&& dlstatus
== DLADM_STATUS_OK
) {
706 if (zone_check_datalink(&zoneid
, linkid
) == 0) {
707 /* interface is in use by a non-global zone. */
708 return (IPADM_IF_INUSE
);
712 /* loopback interfaces are just added as logical interface */
713 bzero(&lifr
, sizeof (lifr
));
714 islo
= i_ipadm_is_loopback(ifname
);
715 if (islo
|| i_ipadm_get_lnum(ifname
) != 0) {
716 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
718 sock
= iph
->iph_sock
;
720 sock
= iph
->iph_sock6
;
721 if (islo
&& ioctl(sock
, SIOCGLIFADDR
, (caddr_t
)&lifr
) >= 0)
722 return (IPADM_IF_EXISTS
);
723 if (ioctl(sock
, SIOCLIFADDIF
, (caddr_t
)&lifr
) < 0)
724 return (ipadm_errno2status(errno
));
727 * By default, kernel configures 127.0.0.1 on the loopback
728 * interface. Replace this with 0.0.0.0 to be consistent
729 * with interface creation on other physical interfaces.
731 if (islo
&& !legacy
) {
732 bzero(&lifr
.lifr_addr
, sizeof (lifr
.lifr_addr
));
733 lifr
.lifr_addr
.ss_family
= af
;
734 if (ioctl(sock
, SIOCSLIFADDR
, (caddr_t
)&lifr
) < 0)
735 return (ipadm_errno2status(errno
));
737 status
= i_ipadm_persist_if(iph
, ifname
, af
);
738 if (status
!= IPADM_SUCCESS
) {
739 (void) i_ipadm_delete_if(iph
, ifname
,
740 af
, IPADM_OPT_ACTIVE
);
747 dlpi_flags
= DLPI_NOATTACH
;
750 * If IPADM_OPT_IPMP is specified, then this is a request
751 * to create an IPMP interface atop /dev/ipmpstub0. (We can't simply
752 * pass "ipmpstub0" as devname since an admin *could* have a normal
753 * vanity-named link named "ipmpstub0" that they'd like to plumb.)
755 if (ipadm_flags
& IPADM_OPT_IPMP
) {
756 dlpi_flags
|= DLPI_DEVONLY
;
757 linkname
= "ipmpstub0";
760 * Verify that the user is not creating a persistent
761 * IP interface on a non-persistent data-link.
763 if (!i_ipadm_is_vni(ifname
) && dlstatus
== DLADM_STATUS_OK
&&
764 is_persistent
&& !(dlflags
& DLADM_OPT_PERSIST
)) {
765 return (IPADM_TEMPORARY_OBJ
);
771 * We use DLPI_NOATTACH because the ip module will do the attach
772 * itself for DLPI style-2 devices.
774 if (dlpi_open(linkname
, &dh_ip
, dlpi_flags
) != DLPI_SUCCESS
)
775 return (IPADM_DLPI_FAILURE
);
776 ip_fd
= dlpi_fd(dh_ip
);
777 if (ioctl(ip_fd
, I_PUSH
, IP_MOD_NAME
) == -1) {
778 status
= ipadm_errno2status(errno
);
783 * Set IFF_IPV4/IFF_IPV6 flags. The kernel only allows modifications
784 * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL.
788 /* Set the name string and the IFF_IPV* flag */
794 * With the legacy method, the link-local address should be
795 * configured as part of the interface plumb, using the default
796 * token. If IPH_LEGACY is not specified, we want to set :: as
797 * the address and require the admin to explicitly call
798 * ipadm_create_addr() with the address object type set to
799 * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address
800 * as well as the autoconfigured addresses.
802 if (!legacy
&& !i_ipadm_is_6to4(iph
, ifname
))
803 ifflags
|= IFF_NOLINKLOCAL
;
805 (void) strlcpy(newif
, ifname
, sizeof (newif
));
806 status
= i_ipadm_slifname(iph
, ifname
, newif
, ifflags
, ip_fd
,
808 if (status
!= IPADM_SUCCESS
)
811 /* Get the full set of existing flags for this stream */
812 status
= i_ipadm_get_flags(iph
, newif
, af
, &ifflags
);
813 if (status
!= IPADM_SUCCESS
)
816 udp_dev_name
= (af
== AF_INET6
? UDP6_DEV_NAME
: UDP_DEV_NAME
);
817 status
= ipadm_open_arp_on_udp(udp_dev_name
, &mux_fd
);
818 if (status
!= IPADM_SUCCESS
)
821 /* Check if arp is not needed */
822 if (ifflags
& (IFF_NOARP
|IFF_IPV6
)) {
824 * PLINK the interface stream so that the application can exit
825 * without tearing down the stream.
827 if ((ip_muxid
= ioctl(mux_fd
, I_PLINK
, ip_fd
)) == -1)
828 status
= ipadm_errno2status(errno
);
833 * This interface does use ARP, so set up a separate stream
834 * from the interface to ARP.
836 * We use DLPI_NOATTACH because the arp module will do the attach
837 * itself for DLPI style-2 devices.
839 if (dlpi_open(linkname
, &dh_arp
, dlpi_flags
) != DLPI_SUCCESS
) {
840 status
= IPADM_DLPI_FAILURE
;
844 arp_fd
= dlpi_fd(dh_arp
);
845 if (ioctl(arp_fd
, I_PUSH
, ARP_MOD_NAME
) == -1) {
846 status
= ipadm_errno2status(errno
);
850 status
= i_ipadm_slifname_arp(newif
, ifflags
, arp_fd
);
851 if (status
!= IPADM_SUCCESS
)
854 * PLINK the IP and ARP streams so that ifconfig can exit
855 * without tearing down the stream.
857 if ((ip_muxid
= ioctl(mux_fd
, I_PLINK
, ip_fd
)) == -1) {
858 status
= ipadm_errno2status(errno
);
862 if (ioctl(mux_fd
, I_PLINK
, arp_fd
) < 0) {
863 status
= ipadm_errno2status(errno
);
864 (void) ioctl(mux_fd
, I_PUNLINK
, ip_muxid
);
873 (void) close(mux_fd
);
875 if (status
== IPADM_SUCCESS
) {
876 /* copy back new ifname */
877 (void) strlcpy(ifname
, newif
, LIFNAMSIZ
);
879 * If it is a 6to4 tunnel, create a default
880 * addrobj name for the default address on the 0'th
881 * logical interface and set IFF_UP in the interface flags.
883 if (i_ipadm_is_6to4(iph
, ifname
)) {
884 struct ipadm_addrobj_s addr
;
886 i_ipadm_init_addr(&addr
, ifname
, "", IPADM_ADDR_STATIC
);
888 status
= i_ipadm_lookupadd_addrobj(iph
, &addr
);
889 if (status
!= IPADM_SUCCESS
)
891 status
= ipadm_add_aobjname(iph
, ifname
,
892 af
, addr
.ipadm_aobjname
, IPADM_ADDR_STATIC
, 0);
893 if (status
!= IPADM_SUCCESS
)
895 addr
.ipadm_lifnum
= 0;
896 i_ipadm_addrobj2lifname(&addr
, lifname
,
898 status
= i_ipadm_set_flags(iph
, lifname
, af
,
900 if (status
!= IPADM_SUCCESS
)
904 * Prevent static IPv6 addresses from triggering
905 * autoconf. This does not have to be done for
906 * 6to4 tunnel interfaces, since in.ndpd will
907 * not autoconfigure those interfaces.
909 if (af
== AF_INET6
&& !legacy
)
910 (void) i_ipadm_disable_autoconf(newif
);
914 * If IPADM_OPT_PERSIST was set in flags, store the
915 * interface in persistent DB.
918 status
= i_ipadm_persist_if(iph
, newif
, af
);
919 if (status
!= IPADM_SUCCESS
) {
920 (void) i_ipadm_delete_if(iph
, newif
, af
,
925 if (status
== IPADM_EXISTS
)
926 status
= IPADM_IF_EXISTS
;
931 * Unplumbs the interface in `ifname' of family `af'.
934 i_ipadm_unplumb_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
)
936 int ip_muxid
, arp_muxid
;
941 boolean_t changed_arp_muxid
= B_FALSE
;
944 ipadm_status_t ret
= IPADM_SUCCESS
;
946 lifgroupinfo_t lifgr
;
947 ifaddrlistx_t
*ifaddrs
, *ifaddrp
;
948 boolean_t v6
= (af
== AF_INET6
);
950 /* Just do SIOCLIFREMOVEIF on loopback interfaces */
951 bzero(&lifr
, sizeof (lifr
));
952 if (i_ipadm_is_loopback(ifname
) ||
953 (i_ipadm_get_lnum(ifname
) != 0 && (iph
->iph_flags
& IPH_LEGACY
))) {
954 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
955 if (ioctl((af
== AF_INET
) ? iph
->iph_sock
: iph
->iph_sock6
,
956 SIOCLIFREMOVEIF
, (caddr_t
)&lifr
) < 0) {
957 return (ipadm_errno2status(errno
));
959 return (IPADM_SUCCESS
);
963 * We used /dev/udp or udp6 to set up the mux. So we have to use
964 * the same now for PUNLINK also.
967 udp_dev_name
= UDP6_DEV_NAME
;
968 sock
= iph
->iph_sock6
;
970 udp_dev_name
= UDP_DEV_NAME
;
971 sock
= iph
->iph_sock
;
973 if ((muxid_fd
= open(udp_dev_name
, O_RDWR
)) == -1) {
974 ret
= ipadm_errno2status(errno
);
977 ret
= ipadm_open_arp_on_udp(udp_dev_name
, &mux_fd
);
978 if (ret
!= IPADM_SUCCESS
)
980 (void) strlcpy(lifr
.lifr_name
, ifname
, sizeof (lifr
.lifr_name
));
981 if (ioctl(muxid_fd
, SIOCGLIFFLAGS
, (caddr_t
)&lifr
) < 0) {
982 ret
= ipadm_errno2status(errno
);
985 flags
= lifr
.lifr_flags
;
987 if (flags
& IFF_IPMP
) {
989 * There are two reasons the I_PUNLINK can fail with EBUSY:
990 * (1) if IP interfaces are in the group, or (2) if IPMP data
991 * addresses are administratively up. For case (1), we fail
992 * here with a specific error message. For case (2), we bring
993 * down the addresses prior to doing the I_PUNLINK. If the
994 * I_PUNLINK still fails with EBUSY then the configuration
995 * must have changed after our checks, in which case we branch
996 * back up to `again' and rerun this logic. The net effect is
997 * that unplumbing an IPMP interface will only fail with EBUSY
998 * if IP interfaces are in the group.
1000 if (ioctl(sock
, SIOCGLIFGROUPNAME
, &lifr
) == -1) {
1001 ret
= ipadm_errno2status(errno
);
1004 (void) strlcpy(lifgr
.gi_grname
, lifr
.lifr_groupname
,
1006 if (ioctl(sock
, SIOCGLIFGROUPINFO
, &lifgr
) == -1) {
1007 ret
= ipadm_errno2status(errno
);
1010 if ((v6
&& lifgr
.gi_nv6
!= 0) || (!v6
&& lifgr
.gi_nv4
!= 0)) {
1011 ret
= IPADM_GRP_NOTEMPTY
;
1016 * The kernel will fail the I_PUNLINK if the IPMP interface
1017 * has administratively up addresses; bring them down.
1019 if (ifaddrlistx(ifname
, IFF_UP
|IFF_DUPLICATE
,
1020 0, &ifaddrs
) == -1) {
1021 ret
= ipadm_errno2status(errno
);
1025 for (; ifaddrp
!= NULL
; ifaddrp
= ifaddrp
->ia_next
) {
1026 int sock
= (ifaddrp
->ia_flags
& IFF_IPV4
) ?
1027 iph
->iph_sock
: iph
->iph_sock6
;
1028 struct lifreq lifrl
;
1030 if (((ifaddrp
->ia_flags
& IFF_IPV6
) && !v6
) ||
1031 (!(ifaddrp
->ia_flags
& IFF_IPV6
) && v6
))
1034 bzero(&lifrl
, sizeof (lifrl
));
1035 (void) strlcpy(lifrl
.lifr_name
, ifaddrp
->ia_name
,
1036 sizeof (lifrl
.lifr_name
));
1037 if (ioctl(sock
, SIOCGLIFFLAGS
, &lifrl
) < 0) {
1038 ret
= ipadm_errno2status(errno
);
1039 ifaddrlistx_free(ifaddrs
);
1042 if (lifrl
.lifr_flags
& IFF_UP
) {
1043 ret
= i_ipadm_set_flags(iph
, lifrl
.lifr_name
,
1044 ((lifrl
.lifr_flags
& IFF_IPV4
) ? AF_INET
:
1045 AF_INET6
), 0, IFF_UP
);
1046 if (ret
!= IPADM_SUCCESS
) {
1047 ifaddrlistx_free(ifaddrs
);
1050 } else if (lifrl
.lifr_flags
& IFF_DUPLICATE
) {
1051 if (ioctl(sock
, SIOCGLIFADDR
, &lifrl
) < 0 ||
1052 ioctl(sock
, SIOCSLIFADDR
, &lifrl
) < 0) {
1053 ret
= ipadm_errno2status(errno
);
1054 ifaddrlistx_free(ifaddrs
);
1059 ifaddrlistx_free(ifaddrs
);
1062 if (ioctl(muxid_fd
, SIOCGLIFMUXID
, (caddr_t
)&lifr
) < 0) {
1063 ret
= ipadm_errno2status(errno
);
1066 arp_muxid
= lifr
.lifr_arp_muxid
;
1067 ip_muxid
= lifr
.lifr_ip_muxid
;
1070 * We don't have a good way of knowing whether the arp stream is
1071 * plumbed. We can't rely on IFF_NOARP because someone could
1072 * have turned it off later using "ifconfig xxx -arp".
1074 if (arp_muxid
!= 0) {
1075 if (ioctl(mux_fd
, I_PUNLINK
, arp_muxid
) < 0) {
1077 * See the comment before the SIOCGLIFGROUPNAME call.
1079 if (errno
== EBUSY
&& (flags
& IFF_IPMP
))
1082 if ((errno
== EINVAL
) &&
1083 (flags
& (IFF_NOARP
| IFF_IPV6
))) {
1085 * Some plumbing utilities set the muxid to
1086 * -1 or some invalid value to signify that
1087 * there is no arp stream. Set the muxid to 0
1088 * before trying to unplumb the IP stream.
1089 * IP does not allow the IP stream to be
1090 * unplumbed if it sees a non-null arp muxid,
1091 * for consistency of IP-ARP streams.
1093 lifr
.lifr_arp_muxid
= 0;
1094 (void) ioctl(muxid_fd
, SIOCSLIFMUXID
,
1096 changed_arp_muxid
= B_TRUE
;
1099 * In case of any other error, we continue with
1105 if (ioctl(mux_fd
, I_PUNLINK
, ip_muxid
) < 0) {
1106 if (changed_arp_muxid
) {
1108 * Some error occurred, and we need to restore
1109 * everything back to what it was.
1112 lifr
.lifr_arp_muxid
= arp_muxid
;
1113 lifr
.lifr_ip_muxid
= ip_muxid
;
1114 (void) ioctl(muxid_fd
, SIOCSLIFMUXID
, (caddr_t
)&lifr
);
1118 * See the comment before the SIOCGLIFGROUPNAME call.
1120 if (errno
== EBUSY
&& (flags
& IFF_IPMP
))
1123 ret
= ipadm_errno2status(errno
);
1127 (void) close(muxid_fd
);
1129 (void) close(mux_fd
);
1131 if (af
== AF_INET6
&& ret
== IPADM_SUCCESS
) {
1133 * in.ndpd maintains the phyints in its memory even after
1134 * the interface is plumbed, so that it can be reused when
1135 * the interface gets plumbed again. The default behavior
1136 * of in.ndpd is to start autoconfiguration for an interface
1137 * that gets plumbed. We need to send the
1138 * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this
1139 * default behavior on replumb.
1141 (void) i_ipadm_enable_autoconf(ifname
);
1147 * Saves the given interface name `ifname' with address family `af' in
1150 static ipadm_status_t
1151 i_ipadm_persist_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
)
1153 ipmgmt_if_arg_t ifarg
;
1156 (void) strlcpy(ifarg
.ia_ifname
, ifname
, sizeof (ifarg
.ia_ifname
));
1157 ifarg
.ia_family
= af
;
1158 ifarg
.ia_cmd
= IPMGMT_CMD_SETIF
;
1159 ifarg
.ia_flags
= IPMGMT_PERSIST
;
1160 err
= ipadm_door_call(iph
, &ifarg
, sizeof (ifarg
), NULL
, 0, B_FALSE
);
1161 return (ipadm_errno2status(err
));
1165 * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST
1166 * is set in `ipadm_flags', it is also removed from persistent configuration.
1169 i_ipadm_delete_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
1170 uint32_t ipadm_flags
)
1172 ipadm_status_t ret
= IPADM_SUCCESS
;
1173 ipadm_status_t db_status
;
1174 char tmp_ifname
[LIFNAMSIZ
];
1176 struct ipadm_addrobj_s ipaddr
;
1177 boolean_t is_persistent
=
1178 (ipadm_flags
& IPADM_OPT_PERSIST
);
1180 ret
= i_ipadm_unplumb_if(iph
, ifname
, af
);
1181 if (ret
!= IPADM_SUCCESS
)
1184 cp
= strrchr(ifname
, IPADM_LOGICAL_SEP
);
1186 assert(iph
->iph_flags
& IPH_LEGACY
);
1188 * This is a non-zero logical interface.
1189 * Find the addrobj and remove it from the daemon's memory.
1191 (void) strlcpy(tmp_ifname
, ifname
, sizeof (tmp_ifname
));
1192 tmp_ifname
[cp
- ifname
] = '\0';
1194 ipaddr
.ipadm_lifnum
= atoi(cp
);
1195 (void) strlcpy(ipaddr
.ipadm_ifname
, tmp_ifname
,
1196 sizeof (ipaddr
.ipadm_ifname
));
1197 ipaddr
.ipadm_af
= af
;
1198 ret
= i_ipadm_get_lif2addrobj(iph
, &ipaddr
);
1199 if (ret
== IPADM_SUCCESS
) {
1200 ret
= i_ipadm_delete_addrobj(iph
, &ipaddr
,
1202 } else if (ret
== IPADM_NOTFOUND
) {
1203 ret
= IPADM_SUCCESS
;
1209 * Even if interface does not exist, remove all its addresses and
1210 * properties from the persistent store. If interface does not
1211 * exist both in kernel and the persistent store, return IPADM_ENXIO.
1213 if ((ret
== IPADM_ENXIO
&& is_persistent
) || ret
== IPADM_SUCCESS
) {
1214 db_status
= i_ipadm_delete_ifobj(iph
, ifname
, af
,
1216 if (db_status
== IPADM_SUCCESS
)
1217 ret
= IPADM_SUCCESS
;
1224 * Resets all addresses on interface `ifname' with address family `af'
1225 * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties
1226 * and address objects of `ifname' for `af' are also removed from the
1230 i_ipadm_delete_ifobj(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
1231 boolean_t is_persistent
)
1233 ipmgmt_if_arg_t ifarg
;
1236 ifarg
.ia_cmd
= IPMGMT_CMD_RESETIF
;
1237 ifarg
.ia_flags
= IPMGMT_ACTIVE
;
1239 ifarg
.ia_flags
|= IPMGMT_PERSIST
;
1240 ifarg
.ia_family
= af
;
1241 (void) strlcpy(ifarg
.ia_ifname
, ifname
, LIFNAMSIZ
);
1243 err
= ipadm_door_call(iph
, &ifarg
, sizeof (ifarg
), NULL
, 0, B_FALSE
);
1244 return (ipadm_errno2status(err
));
1248 * Create the interface by plumbing it for IP.
1249 * This function will check if there is saved configuration information
1250 * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space
1251 * for `ifname' is taken.
1254 i_ipadm_create_if(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
1255 uint32_t ipadm_flags
)
1257 ipadm_status_t status
;
1259 sa_family_t other_af
;
1262 * Return error, if the interface already exists in either the active
1263 * or the persistent configuration.
1265 if (ipadm_if_enabled(iph
, ifname
, af
))
1266 return (IPADM_IF_EXISTS
);
1268 if (!(iph
->iph_flags
& IPH_LEGACY
)) {
1269 status
= i_ipadm_if_pexists(iph
, ifname
, af
, &p_exists
);
1270 if (status
!= IPADM_SUCCESS
)
1272 other_af
= (af
== AF_INET
? AF_INET6
: AF_INET
);
1274 if (!ipadm_if_enabled(iph
, ifname
, other_af
))
1275 return (IPADM_OP_DISABLE_OBJ
);
1277 ipadm_flags
&= ~IPADM_OPT_PERSIST
;
1281 return (i_ipadm_plumb_if(iph
, ifname
, af
, ipadm_flags
));
1285 * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by
1286 * default, unless a value in `af' is specified. The interface may be plumbed
1287 * only if there is no previously saved persistent configuration information
1288 * for the interface (in which case the ipadm_enable_if() function must
1289 * be used to enable the interface).
1291 * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS,
1292 * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE,
1293 * or appropriate ipadm_status_t corresponding to the errno.
1295 * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may
1296 * be over-written with the actual interface name when a PPA has to be
1297 * internally generated by the library.
1300 ipadm_create_if(ipadm_handle_t iph
, char *ifname
, sa_family_t af
,
1303 ipadm_status_t status
;
1304 boolean_t created_v4
= B_FALSE
;
1305 char newifname
[LIFNAMSIZ
];
1307 /* Check for the required authorization */
1308 if (!ipadm_check_auth())
1309 return (IPADM_EAUTH
);
1311 if (flags
== 0 || ((flags
& IPADM_OPT_PERSIST
) &&
1312 !(flags
& IPADM_OPT_ACTIVE
)) ||
1313 (flags
& ~(IPADM_COMMON_OPT_MASK
| IPADM_OPT_IPMP
|
1314 IPADM_OPT_GENPPA
))) {
1315 return (IPADM_INVALID_ARG
);
1317 if (flags
& IPADM_OPT_GENPPA
) {
1318 if (snprintf(newifname
, LIFNAMSIZ
, "%s0", ifname
) >=
1320 return (IPADM_INVALID_ARG
);
1322 if (strlcpy(newifname
, ifname
, LIFNAMSIZ
) >= LIFNAMSIZ
)
1323 return (IPADM_INVALID_ARG
);
1326 if (!i_ipadm_validate_ifname(iph
, newifname
))
1327 return (IPADM_INVALID_ARG
);
1329 if ((af
== AF_INET
|| af
== AF_UNSPEC
) &&
1330 !i_ipadm_is_6to4(iph
, ifname
)) {
1331 status
= i_ipadm_create_if(iph
, ifname
, AF_INET
, flags
);
1332 if (status
!= IPADM_SUCCESS
)
1334 created_v4
= B_TRUE
;
1336 if (af
== AF_INET6
|| af
== AF_UNSPEC
) {
1337 status
= i_ipadm_create_if(iph
, ifname
, AF_INET6
, flags
);
1338 if (status
!= IPADM_SUCCESS
) {
1340 (void) i_ipadm_delete_if(iph
, ifname
, AF_INET
,
1347 return (IPADM_SUCCESS
);
1351 * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces
1352 * when `af' = AF_UNSPEC.
1355 ipadm_delete_if(ipadm_handle_t iph
, const char *ifname
, sa_family_t af
,
1358 ipadm_status_t status1
= IPADM_SUCCESS
;
1359 ipadm_status_t status2
= IPADM_SUCCESS
;
1360 ipadm_status_t other
;
1362 /* Check for the required authorization */
1363 if (!ipadm_check_auth())
1364 return (IPADM_EAUTH
);
1366 /* Validate the `ifname' for any logical interface. */
1367 if (flags
== 0 || (flags
& ~(IPADM_COMMON_OPT_MASK
)) ||
1368 !i_ipadm_validate_ifname(iph
, ifname
))
1369 return (IPADM_INVALID_ARG
);
1371 if (af
== AF_INET
|| af
== AF_UNSPEC
)
1372 status1
= i_ipadm_delete_if(iph
, ifname
, AF_INET
, flags
);
1373 if (af
== AF_INET6
|| af
== AF_UNSPEC
)
1374 status2
= i_ipadm_delete_if(iph
, ifname
, AF_INET6
, flags
);
1376 * If the family has been uniquely identified, we return the
1377 * associated status, even if that is ENXIO. Calls from ifconfig
1378 * which can only unplumb one of IPv4/IPv6 at any time fall under
1383 else if (af
== AF_INET6
)
1385 else if (af
!= AF_UNSPEC
)
1386 return (IPADM_INVALID_ARG
);
1389 * If af is AF_UNSPEC, then we return the following:
1390 * status1, if status1 == status2
1391 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS
1392 * and the other status is ENXIO
1393 * IPADM_ENXIO, if both status1 and status2 are ENXIO
1394 * IPADM_FAILURE otherwise.
1396 if (status1
== status2
) {
1397 /* covers the case when both status1 and status2 are ENXIO */
1399 } else if (status1
== IPADM_SUCCESS
|| status2
== IPADM_SUCCESS
) {
1400 if (status1
== IPADM_SUCCESS
)
1404 return (other
== IPADM_ENXIO
? IPADM_SUCCESS
: IPADM_FAILURE
);
1406 return (IPADM_FAILURE
);
1411 * Returns information about all interfaces in both active and persistent
1412 * configuration. If `ifname' is not NULL, it returns only the interface
1413 * identified by `ifname'.
1416 * On success: IPADM_SUCCESS.
1417 * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE.
1420 ipadm_if_info(ipadm_handle_t iph
, const char *ifname
,
1421 ipadm_if_info_t
**if_info
, uint32_t flags
, int64_t lifc_flags
)
1423 ipadm_status_t status
;
1426 if (if_info
== NULL
|| iph
== NULL
|| flags
!= 0)
1427 return (IPADM_INVALID_ARG
);
1429 if (ifname
!= NULL
&&
1430 (!ifparse_ifspec(ifname
, &ifsp
) || ifsp
.ifsp_lunvalid
)) {
1431 return (IPADM_INVALID_ARG
);
1434 status
= i_ipadm_get_all_if_info(iph
, ifname
, if_info
, lifc_flags
);
1435 if (status
!= IPADM_SUCCESS
)
1437 if (ifname
!= NULL
&& *if_info
== NULL
)
1438 return (IPADM_ENXIO
);
1440 return (IPADM_SUCCESS
);
1444 * Frees the linked list allocated by ipadm_if_info().
1447 ipadm_free_if_info(ipadm_if_info_t
*ifinfo
)
1449 ipadm_if_info_t
*ifinfo_next
;
1451 for (; ifinfo
!= NULL
; ifinfo
= ifinfo_next
) {
1452 ifinfo_next
= ifinfo
->ifi_next
;
1458 * Re-enable the interface `ifname' based on the saved configuration
1462 ipadm_enable_if(ipadm_handle_t iph
, const char *ifname
, uint32_t flags
)
1465 ipadm_status_t status
;
1468 /* Check for the required authorization */
1469 if (!ipadm_check_auth())
1470 return (IPADM_EAUTH
);
1472 /* Check for logical interfaces. */
1473 if (!ifparse_ifspec(ifname
, &ifsp
) || ifsp
.ifsp_lunvalid
)
1474 return (IPADM_INVALID_ARG
);
1476 /* Enabling an interface persistently is not supported. */
1477 if (flags
& IPADM_OPT_PERSIST
)
1478 return (IPADM_NOTSUP
);
1481 * Return early by checking if the interface is already enabled.
1483 if (ipadm_if_enabled(iph
, ifname
, AF_INET
) &&
1484 ipadm_if_enabled(iph
, ifname
, AF_INET6
)) {
1485 return (IPADM_IF_EXISTS
);
1488 * Enable the interface and restore all its interface properties
1489 * and address objects.
1491 status
= i_ipadm_init_ifs(iph
, ifname
, &ifnvl
);
1492 if (status
!= IPADM_SUCCESS
)
1495 assert(ifnvl
!= NULL
);
1497 * ipadm_enable_if() does exactly what ipadm_init_ifs() does,
1498 * but only for one interface. We need to set IPH_INIT because
1499 * ipmgmtd daemon does not have to write the interface to persistent
1500 * db. The interface is already available in persistent db
1501 * and we are here to re-enable the persistent configuration.
1503 iph
->iph_flags
|= IPH_INIT
;
1504 status
= i_ipadm_init_ifobj(iph
, ifname
, ifnvl
);
1505 iph
->iph_flags
&= ~IPH_INIT
;
1512 * Disable the interface `ifname' by removing it from the active configuration.
1513 * Error code return values follow the model in ipadm_delete_if()
1516 ipadm_disable_if(ipadm_handle_t iph
, const char *ifname
, uint32_t flags
)
1518 ipadm_status_t status1
, status2
, other
;
1521 /* Check for the required authorization */
1522 if (!ipadm_check_auth())
1523 return (IPADM_EAUTH
);
1525 /* Check for logical interfaces. */
1526 if (!ifparse_ifspec(ifname
, &ifsp
) || ifsp
.ifsp_lunvalid
)
1527 return (IPADM_INVALID_ARG
);
1529 /* Disabling an interface persistently is not supported. */
1530 if (flags
& IPADM_OPT_PERSIST
)
1531 return (IPADM_NOTSUP
);
1533 status1
= i_ipadm_unplumb_if(iph
, ifname
, AF_INET6
);
1534 if (status1
== IPADM_SUCCESS
)
1535 status1
= i_ipadm_delete_ifobj(iph
, ifname
, AF_INET6
, B_FALSE
);
1536 status2
= i_ipadm_unplumb_if(iph
, ifname
, AF_INET
);
1537 if (status2
== IPADM_SUCCESS
)
1538 status2
= i_ipadm_delete_ifobj(iph
, ifname
, AF_INET
, B_FALSE
);
1539 if (status1
== status2
) {
1541 } else if (status1
== IPADM_SUCCESS
|| status2
== IPADM_SUCCESS
) {
1542 if (status1
== IPADM_SUCCESS
)
1546 return (other
== IPADM_ENXIO
? IPADM_SUCCESS
: IPADM_FAILURE
);
1548 return (IPADM_FAILURE
);
1553 * This workaround is until libipadm supports IPMP and is required whenever an
1554 * interface is moved into an IPMP group. Since libipadm doesn't support IPMP
1555 * yet, we will have to update the daemon's in-memory mapping of
1556 * `aobjname' to 'lifnum'.
1558 * For `IPMGMT_ACTIVE' case, i_ipadm_delete_ifobj() would only fail if
1559 * door_call(3C) fails. Also, there is no use in returning error because
1560 * `ifname' would have been successfuly moved into IPMP group, by this time.
1563 ipadm_if_move(ipadm_handle_t iph
, const char *ifname
)
1565 (void) i_ipadm_delete_ifobj(iph
, ifname
, AF_INET
, B_FALSE
);
1566 (void) i_ipadm_delete_ifobj(iph
, ifname
, AF_INET6
, B_FALSE
);