ipadm_if.c revision 6e91bba0d6c6bdabbba62cefae583715a4a58e2a
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2N/A * Use is subject to license terms. 2N/A * Returns B_FALSE if the interface in `ifname' has at least one address that is 2N/A * IFF_UP in the addresses in `ifa'. 2N/A * If this condition is true, there is at least one 2N/A * address that is IFF_UP. So, we need to return B_FALSE. 2N/A /* We did not find any IFF_UP addresses. */ 2N/A * Retrieves the information for the interface `ifname' from active 2N/A * config if `ifname' is specified and returns the result in the list `if_info'. 2N/A * Otherwise, it retrieves the information for all the interfaces in 2N/A * the active config and returns the result in the list `if_info'. 2N/A * Get information for all interfaces. 2N/A /* Skip interfaces with logical num != 0 */ 2N/A * Skip the current interface if a specific `ifname' has 2N/A * been requested and current interface does not match 2N/A * Check if the interface already exists in our list. 2N/A * If it already exists, we need to update its flags. 2N/A /* Update the `ifi_next' pointer for this new node */ 2N/A * Retrieve the flags for the interface by doing a 2N/A * SIOCGLIFFLAGS to populate the `ifi_cflags' field. 2N/A * Returns the interface information for `ifname' in `if_info' from persistent 2N/A * config if `ifname' is non-null. Otherwise, it returns all the interfaces 2N/A * from persistent config in `if_info'. 2N/A * Collects information for `ifname' if one is specified from both 2N/A * active and persistent config in `if_info'. If no `ifname' is specified, 2N/A * this returns all the interfaces in active and persistent config in 2N/A * Retrive the information for the requested `ifname' or all 2N/A * interfaces from active configuration. 2N/A /* Get the interface state for each interface in `aifinfo'. */ 2N/A /* We need all addresses to get the interface state */ 2N/A * Find the `ifaddrs' structure from `ifa' 2N/A * for this interface. We need the IFF_* flags 2N/A * to find the interface state. 2N/A * The interface might have been removed 2N/A * from kernel. Retry getting all the active 2N/A * Get the persistent interface information in `pifinfo'. 2N/A * If a persistent interface is also found in `aifinfo', update 2N/A * its entry in `aifinfo' with the persistent information from 2N/A * `pifinfo'. If an interface is found in `pifinfo', but not in 2N/A * `aifinfo', it means that this interface was disabled. We should 2N/A * add this interface to `aifinfo' and set it state to IFIF_DISABLED. 2N/A * Sets the output argument `exists' to true or false based on whether 2N/A * any persistent configuration is available for `ifname' and returns 2N/A * IPADM_SUCCESS as status. If the persistent information cannot be retrieved, 2N/A * `exists' is unmodified and an error status is returned. 2N/A * Open "/dev/udp{,6}" for use as a multiplexor to PLINK the interface stream 2N/A * under. We use "/dev/udp" instead of "/dev/ip" since STREAMS will not let 2N/A * you PLINK a driver under itself, and "/dev/ip" is typically the driver at 2N/A * the bottom of the stream for tunneling interfaces. 2N/A * Pop off all undesired modules (note that the user may have 2N/A * configured autopush to add modules above udp), and push the 2N/A * arp module onto the resulting stream. This is used to make 2N/A * IP+ARP be able to atomically track the muxid for the I_PLINKed 2N/A * STREAMS, thus it isn't related to ARP running the ARP protocol. 2N/A * i_ipadm_create_ipmp() is called from i_ipadm_create_ipmp_peer() when an 2N/A * underlying interface in an ipmp group G is plumbed for an address family, 2N/A * but the meta-interface for the other address family `af' does not exist 2N/A * yet for the group G. If `af' is IPv6, we need to bring up the 2N/A * link-local address. 2N/A /* Create the ipmp underlying interface */ 2N/A * To preserve backward-compatibility, always bring up the link-local 2N/A * address for implicitly-created IPv6 IPMP interfaces. 2N/A * If the caller requested a different group name, issue a 2N/A * SIOCSLIFGROUPNAME on the new IPMP interface. 2N/A /* Remove the interface we created. */ 2N/A * Checks if `ifname' is plumbed and in an IPMP group on its "other" address 2N/A * family. If so, create a matching IPMP group for address family `af'. 2N/A * iph is the handle for the interface that we are trying to plumb. 2N/A * other_af_sock is the socket for the "other" address family. 2N/A * If `ifname' *is* the IPMP group interface, or if the relevant 2N/A * address family is already configured, then there's nothing to do. 2N/A * Issues the ioctl SIOCSLIFNAME to kernel on the given ARP stream fd. 2N/A * Tell ARP the name and unit number for this interface. 2N/A * Note that arp has no support for transparent ioctls. 2N/A * Issues the ioctl SIOCSLIFNAME to kernel. If IPADM_OPT_GENPPA is set in 2N/A * `ipadm_flags', then a ppa will be generated. `newif' will be updated 2N/A * with the generated ppa. 2N/A * We'd like to just set lifr_ppa to UINT_MAX and have the 2N/A * kernel pick a PPA. Unfortunately, that would mishandle 2N/A * 1. If the PPA is available but the groupname is taken 2N/A * (e.g., the "ipmp2" IP interface name is available 2N/A * but the "ipmp2" groupname is taken) then the 2N/A * auto-assignment by the kernel will fail. 2N/A * 2. If we're creating (e.g.) an IPv6-only IPMP 2N/A * interface, and there's already an IPv4-only IPMP 2N/A * interface, the kernel will allow us to accidentally 2N/A * reuse the IPv6 IPMP interface name (since 2N/A * SIOCSLIFNAME uniqueness is per-interface-type). 2N/A * This will cause administrative confusion. 2N/A * Thus, we instead take a brute-force approach of checking 2N/A * whether the IPv4 or IPv6 name is already in-use before 2N/A * attempting the SIOCSLIFNAME. As per (1) above, the 2N/A * SIOCSLIFNAME may still fail, in which case we just proceed 2N/A * to the next one. If this approach becomes too slow, we 2N/A * can add a new SIOC* to handle this case in the kernel. 2N/A * PPA has been successfully established. 2N/A * Update `newif' with the ppa. 2N/A /* We should have already validated the interface name. */ 2N/A * Before we call SIOCSLIFNAME, ensure that the IPMP group 2N/A * interface for this address family exists. Otherwise, the 2N/A * kernel will kick the interface out of the group when we do 2N/A * Example: suppose bge0 is plumbed for IPv4 and in group "a". 2N/A * If we're now plumbing bge0 for IPv6, but the IPMP group 2N/A * interface for "a" is not plumbed for IPv6, the SIOCSLIFNAME 2N/A * will kick bge0 out of group "a", which is undesired. 2N/A * Plumbs the interface `ifname' for the address family `af'. It also persists 2N/A * the interface for `af' if IPADM_OPT_PERSIST is set in `ipadm_flags'. 2N/A * If we're in the global zone and we're plumbing a datalink, make 2N/A * sure that the datalink is not assigned to a non-global zone. Note 2N/A * that the non-global zones don't need this check, because zoneadm 2N/A * has taken care of this when the zones boot. 2N/A /* interface is in use by a non-global zone. */ 2N/A /* loopback interfaces are just added as logical interface */ 2N/A * By default, kernel configures 127.0.0.1 on the loopback 2N/A * interface. Replace this with 0.0.0.0 to be consistent 2N/A * with interface creation on other physical interfaces. 2N/A * If IPADM_OPT_IPMP is specified, then this is a request 2N/A * pass "ipmpstub0" as devname since an admin *could* have a normal 2N/A * vanity-named link named "ipmpstub0" that they'd like to plumb.) 2N/A * Verify that the user is not creating a persistent 2N/A * IP interface on a non-persistent data-link. 2N/A * We use DLPI_NOATTACH because the ip module will do the attach 2N/A * itself for DLPI style-2 devices. 2N/A * to IFF_IPv4, IFF_IPV6, IFF_BROADCAST, IFF_XRESOLV, IFF_NOLINKLOCAL. 2N/A /* Set the name string and the IFF_IPV* flag */ 2N/A * With the legacy method, the link-local address should be 2N/A * configured as part of the interface plumb, using the default 2N/A * token. If IPH_LEGACY is not specified, we want to set :: as 2N/A * the address and require the admin to explicitly call 2N/A * ipadm_create_addr() with the address object type set to 2N/A * IPADM_ADDR_IPV6_ADDRCONF to create the link-local address 2N/A * as well as the autoconfigured addresses. 2N/A /* Get the full set of existing flags for this stream */ 2N/A /* Check if arp is not needed */ 2N/A * PLINK the interface stream so that the application can exit 2N/A * without tearing down the stream. 2N/A * This interface does use ARP, so set up a separate stream 2N/A * from the interface to ARP. 2N/A * We use DLPI_NOATTACH because the arp module will do the attach 2N/A * itself for DLPI style-2 devices. 2N/A * PLINK the IP and ARP streams so that ifconfig can exit 2N/A * without tearing down the stream. 2N/A /* copy back new ifname */ 2N/A * If it is a 6to4 tunnel, create a default 2N/A * addrobj name for the default address on the 0'th 2N/A * logical interface and set IFF_UP in the interface flags. 2N/A * Prevent static IPv6 addresses from triggering 2N/A * autoconf. This does not have to be done for 2N/A * 6to4 tunnel interfaces, since in.ndpd will 2N/A * not autoconfigure those interfaces. 2N/A * If IPADM_OPT_PERSIST was set in flags, store the 2N/A * interface in persistent DB. 2N/A * Unplumbs the interface in `ifname' of family `af'. 2N/A /* Just do SIOCLIFREMOVEIF on loopback interfaces */ 2N/A * We used /dev/udp or udp6 to set up the mux. So we have to use 2N/A * the same now for PUNLINK also. * There are two reasons the I_PUNLINK can fail with EBUSY: * (1) if IP interfaces are in the group, or (2) if IPMP data * addresses are administratively up. For case (1), we fail * here with a specific error message. For case (2), we bring * down the addresses prior to doing the I_PUNLINK. If the * I_PUNLINK still fails with EBUSY then the configuration * must have changed after our checks, in which case we branch * back up to `again' and rerun this logic. The net effect is * that unplumbing an IPMP interface will only fail with EBUSY * if IP interfaces are in the group. * The kernel will fail the I_PUNLINK if the IPMP interface * has administratively up addresses; bring them down. * We don't have a good way of knowing whether the arp stream is * plumbed. We can't rely on IFF_NOARP because someone could * have turned it off later using "ifconfig xxx -arp". * See the comment before the SIOCGLIFGROUPNAME call. * Some plumbing utilities set the muxid to * -1 or some invalid value to signify that * there is no arp stream. Set the muxid to 0 * before trying to unplumb the IP stream. * IP does not allow the IP stream to be * unplumbed if it sees a non-null arp muxid, * for consistency of IP-ARP streams. * In case of any other error, we continue with * Some error occurred, and we need to restore * everything back to what it was. * See the comment before the SIOCGLIFGROUPNAME call. * in.ndpd maintains the phyints in its memory even after * the interface is plumbed, so that it can be reused when * the interface gets plumbed again. The default behavior * of in.ndpd is to start autoconfiguration for an interface * that gets plumbed. We need to send the * message IPADM_ENABLE_AUTOCONF to in.ndpd to restore this * default behavior on replumb. * Saves the given interface name `ifname' with address family `af' in * Remove the IP interface from active configuration. If IPADM_OPT_PERSIST * is set in `ipadm_flags', it is also removed from persistent configuration. * This is a non-zero logical interface. * Find the addrobj and remove it from the daemon's memory. * Even if interface does not exist, remove all its addresses and * properties from the persistent store. If interface does not * exist both in kernel and the persistent store, return IPADM_ENXIO. * Resets all addresses on interface `ifname' with address family `af' * from ipmgmtd daemon. If is_persistent = B_TRUE, all interface properties * and address objects of `ifname' for `af' are also removed from the * Create the interface by plumbing it for IP. * This function will check if there is saved configuration information * for `ifname' and return IPADM_OP_DISABLE_OBJ if the name-space * Return error, if the interface already exists in either the active * or the persistent configuration. * Plumbs an interface. Creates both IPv4 and IPv6 interfaces by * default, unless a value in `af' is specified. The interface may be plumbed * only if there is no previously saved persistent configuration information * for the interface (in which case the ipadm_enable_if() function must * be used to enable the interface). * Returns: IPADM_SUCCESS, IPADM_FAILURE, IPADM_IF_EXISTS, * IPADM_IF_PERSIST_EXISTS, IPADM_DLPI_FAILURE, * or appropriate ipadm_status_t corresponding to the errno. * `ifname' must point to memory that can hold upto LIFNAMSIZ chars. It may * be over-written with the actual interface name when a PPA has to be * internally generated by the library. /* Check for the required authorization */ * Deletes the interface in `ifname'. Removes both IPv4 and IPv6 interfaces /* Check for the required authorization */ /* Validate the `ifname' for any logical interface. */ * If the family has been uniquely identified, we return the * associated status, even if that is ENXIO. Calls from ifconfig * which can only unplumb one of IPv4/IPv6 at any time fall under * If af is AF_UNSPEC, then we return the following: * status1, if status1 == status2 * IPADM_SUCCESS, if either of status1 or status2 is SUCCESS * and the other status is ENXIO * IPADM_ENXIO, if both status1 and status2 are ENXIO * IPADM_FAILURE otherwise. /* covers the case when both status1 and status2 are ENXIO */ * Returns information about all interfaces in both active and persistent * configuration. If `ifname' is not NULL, it returns only the interface * identified by `ifname'. * On success: IPADM_SUCCESS. * On error : IPADM_INVALID_ARG, IPADM_ENXIO or IPADM_FAILURE. * Frees the linked list allocated by ipadm_if_info(). * Re-enable the interface `ifname' based on the saved configuration /* Check for the required authorization */ /* Check for logical interfaces. */ /* Enabling an interface persistently is not supported. */ * Return early by checking if the interface is already enabled. * Enable the interface and restore all its interface properties * ipadm_enable_if() does exactly what ipadm_init_ifs() does, * but only for one interface. We need to set IPH_INIT because * ipmgmtd daemon does not have to write the interface to persistent * db. The interface is already available in persistent db * and we are here to re-enable the persistent configuration. * Disable the interface `ifname' by removing it from the active configuration. * Error code return values follow the model in ipadm_delete_if() /* Check for the required authorization */ /* Check for logical interfaces. */ /* Disabling an interface persistently is not supported. */