ip_arp.c revision a69116193464f859a8b27a2db19ad330ce163a55
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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 2N/A * MAC-specific intelligence. Shouldn't be needed, but the DL_INFO_ACK 2N/A * doesn't quite do it for us. #
define AR_NOTFOUND 1 /* No matching ace found in cache */#
define AR_MERGED 2 /* Matching ace updated (RFC 826 Merge_flag) */#
define AR_LOOPBACK 3 /* Our own arp packet was received */#
define AR_BOGON 4 /* Another host has our IP addr. */#
define AR_FAILED 5 /* Duplicate Address Detection has failed */#
define AR_CHANGED 6 /* Address has changed; tell IP (and merged) */ /* ill_close or arp_unbind_complete may be waiting */ * wake up any pending ip ioctls. * IP addr and hardware address match what we already * have, then this is a broadcast packet emitted by one of our * interfaces, reflected by the switch and received on another * interface. We return AR_LOOPBACK. * If the entry is unverified, then we've just verified that * someone else already owns this address, because this is a * message with the same protocol address but different * If the IP address matches ours and we're authoritative for * this entry, then some other node is using our IP addr, so * return AR_BOGON. Also reset the transmit count to zero so * that, if we're currently in initial announcement mode, we * switch back to the lazier defense mode. Knowing that * there's at least one duplicate out there, we ought not * NCE_F_AUTHORITY is set in one of two ways: * 1. /sbin/arp told us so, via the "permanent" flag. * 2. This is one of my addresses. * No address conflict was detected, and we are getting * ready to update the ncec's hwaddr. The nce MUST NOT be on an * under interface, because all dynamic nce's are created on the * native interface (in the non-IPMP case) or on the IPMP * meta-interface (in the IPMP case) * update ncec with src_haddr, hlen. * So the new_state is at least "STALE". If, in addition, * this a solicited, unicast ARP_RESPONSE, we can transition ip1dbg((
"got info for ncec %p from addr %x\n",
* We don't have the equivalent of the IPv6 'S' flag indicating * a solicited response, so we assume that if we are in * INCOMPLETE, or got back an unchanged lladdr in PROBE state, * and this is an ARP_RESPONSE, it must be a * solicited response allowing us to transtion to REACHABLE. * Call nce_update() to refresh fastpath information on any * dependent nce_t entries. /* Find an entry for a particular MAC type in the arp_m_tbl. */ * Called when an DLPI control message has been acked; send down the next * queued message (if any). * The DLPI messages of interest being bind, attach and unbind since * these are the only ones sent by ARP via arp_dlpi_send. * This routine is called during module initialization when the DL_INFO_ACK * comes back from the device. We set up defaults for all the device dependent * doo-dads we are going to need. This will leave us ready to roll if we are * attempting auto-configuration. Alternatively, these defaults can be * overridden by initialization procedures possessing higher intelligence. * Caller will free the mp. * We initialize based on parameters in the (currently) not too * Note: the arp_hw_type in the arp header may be derived from * the ill_mac_type and arp_m_lookup(). char *,
"<some ioctl>",
char *,
"-",
char *,
"default mblk",
char *,
"-",
* similar to ill_dlpi_pending(): verify that the received DLPI response * matches the one that is pending for the arl. ip0dbg((
"arl_dlpi_pending unsolicited ack for %s on %s",
ip0dbg((
"arl_dlpi_pending ack for %s on %s expect %s",
/* DLPI messages, other than DL_UNITDATA_IND are handled here. */ * If we received an ACK but didn't send a request for it, then it * can't be part of any pending operation; discard up-front. * ce is confused about how DLPI works, so we have to interpret * an "error" on DL_NOTIFY_ACK (which we never could have sent) * as really meaning an error on DL_NOTIFY_REQ. * Note that supporting DL_NOTIFY_REQ is optional, so printing * out an error message on the console isn't warranted except * ill has not been set up yet for this case. This is the * DL_INFO_ACK for the first DL_INFO_REQ sent from * arp_modopen(). There should be no other arl_dlpi_deferred * messages pending. We initialize the arl here. * This is not an error, so we don't set ARL_LL_DOWN * if this is part of the unplumb the arl may * vaporize any moment after we cv_signal the * arl_cv so we reset arl_dlpi_pending here. * All other cases (including replumb) will * have the arl_dlpi_pending reset in * ill ref obtained by arl_to_ill() will be released * Handling of DLPI messages that require exclusive access to the ipsq. * happens as a result arp_modclose triggering unbind. * arp_rput_dlpi will cv_signal the arl_cv and the modclose * will complete, but when it does ipsq_exit, the waiting * qwriter_ip gets into the ipsq but will find the arl null. * There should be no deferred messages in this case, so * just complete and exit. /* If it's anything else, we didn't send it. */ ip0dbg((
"Dropping unrecognized DL_OK_ACK for %s",
* Only allow high priority DLPI messages during unplumb or * replumb, and we don't take an arl_refcnt for that case. * (i) real message from the wire, (DLPI_DATA) * Take a ref on the ill associated with this arl to * prevent the ill from being unplumbed until this thread /* Miscellaneous DLPI messages get shuffled off. */ * What we should have at this point is a DL_UNITDATA_IND message * followed by an ARP packet. We do some initial checks and then * multicast or broadcast packet. Only accept on the ipmp * nominated interface for multicasts ('cast_ill'). * If we have no cast_ill we are liberal and accept everything. /* For an under ill_grp can change under lock */ "for multicast sends and receives",
/* No fooling around with funny messages. */ * hlen 0 is used for RFC 1868 UnARP. * Note that the rest of the code checks that hlen is what we expect * for this hardware address type, so might as well discard packets * Historically, Solaris has been lenient about hardware type numbers. * We should check here, but don't. * If ill is in an ipmp group, it will be the under ill. If we want * to report the packet as coming up the IPMP interface, we should * convert it to the ipmp ill. /* Determine if this is just a probe */ * The following test for loopback is faster than * IP_LOOPBACK_ADDR(), because it avoids any bitwise * Note that these addresses are always in network byte order * ira_ill is the only field used down the arp_notify path. * RFC 826: first check if the <protocol, sender protocol address> is * in the cache, if there is a sender protocol address. Note that this * step also handles resolutions based on source. /* Note: after here we need to freeb(mp) and freemsg(mp1) separately */ * Now look up the destination address. By RFC 826, we ignore the * packet at this step if the target isn't one of our addresses (i.e., * one we have been asked to PUBLISH). This is true even if the * target is something we're trying to resolve and the packet * Let the client know if the source mapping has changed, even * if the destination provides no useful information for the * Check for a reflection. Some misbehaving bridges will * reflect our own transmitted packets back to us. * Responses targeting our HW address that are not responses to * our DAD probe must be ignored as they are related to requests * sent before DAD was restarted. "Response to request that was sent before DAD",
* Responses targeted to HW addresses which are not ours but * sent to our unverified proto address are also conflicts. * These may be reported by a proxy rather than the interface * with the conflicting address, dst_paddr is in conflict * rather than src_paddr. To ensure IP can locate the correct * ipif to take down, it is necessary to copy dst_paddr to * the src_paddr field before sending it to IP. The same is * required for probes, where src_paddr will be INADDR_ANY. * If it's a request, then we reply to this, and if we think the * sender's unknown, then we create an entry to avoid unnecessary ARPs. * The design assumption is that someone ARPing us is likely to send us * a packet soon, and that we'll want to reply to it. * Ignore senders who are deliberately or accidentally * create the ncec for the sender on ipmp_ill. * We pass in the ipmp_ill itself to avoid * creating an nce_t on the under_ill. ip1dbg((
"added ncec %p in state %d ill %s\n",
* Either no memory, or the outgoing interface * latter case, we will fail the send anyway, * and in the former case, we should try to send /* set up cleanup interval on ncec */ * This implements periodic address defense based on a modified * version of the RFC 3927 requirements. Instead of sending a * broadcasted reply every time, as demanded by the RFC, we * send at most one broadcast reply per arp_broadcast_interval. * If this is one of the long-suffering entries, * pull it out now. It no longer needs separate * defense, because we're now doing that with this * Basic initialization of the arl_t and the arl_common structure shared with * By the time we set up the arl, we expect the ETHERTYPE_IP * stream to be fully bound and attached. So we copy/verify * relevant information as possible from/against the ill. * The following should have been set up in arp_ll_set_defaults() * after the first DL_INFO_ACK was received. /* First ensure that the ill is not CONDEMNED. */ /* Allocate and do common initializations for DLPI messages. */ * DLPIv2 says that DL_INFO_REQ and DL_TOKEN_REQ (the latter * of which we don't seem to use) are sent with M_PCPROTO, and * that other DLPI are M_PROTO. /* ioctl not valid when IP opened as a device */ * Find the arl_t that corresponds to this ill_t from the shared * ill_common structure. We can safely access the ai here as it * will only be freed in arp_modclose() after we have become * happens when the arp stream is just being opened, and * arl_ill_init has not been executed yet. * Find the ill_t that corresponds to this arl_t from the shared * arl_common structure. We can safely access the ai here as it * will only be freed in arp_modclose() after we have become /* Allocate and initialize a bind message. */ * Someone is sending ARP packets with a source protocol * address that we have published and for which we believe our * entry is authoritative and verified to be unique on * arp_process_packet() sends AR_CN_FAILED for the case when * a DAD probe is received and the hardware address of a * non-authoritative entry has changed. Thus, AR_CN_BOGON * indicates a real conflict, and we have to do resolution. * We back away quickly from the address if it's from DHCP or * otherwise temporary and hasn't been used recently (or at * all). We'd like to include "deprecated" addresses here as * well (as there's no real reason to defend something we're * discarding), but IPMP "reuses" this flag to mean something * other than the standard meaning. "proxy ARP problem? Node '%s' is using %s on %s",
* ncec_last_time_defended has been adjusted in * ARP gives us a copy of any packet where it thinks * the address has changed, so that we can update our * caches. We're responsible for caching known answers * in the current design. We check whether the * hardware address really has changed in all of our * entries that have cached this mapping, and if so, we * blow them away. This way we will immediately pick * up the rare case of a host changing hardware "node %s is using our IP address %s on %s",
* mp will be freed by arp_excl. * arp_output is called to transmit an ARP Request or Response. The mapping * to RFC 826 variables is: * The ARP frame is sent to the ether_dst in dst_lladdr. /* IFF_NOARP flag is set or link down: do not send arp messages */ /* Fill in the ARP header. */ * Process resolve requests. * If we are not yet reachable then we check and decrease ncec_rcnt; otherwise * we leave it alone (the caller will check and manage ncec_pcnt in those /* not allowed any more retransmits. */ * Some transient error such as ENOMEM or a down link was * encountered. If the link has been taken down permanently, * the ncec will eventually be cleaned up (ipif_down_tail() * will call ipif_nce_down() and flush the ncec), to terminate * recurring attempts to send ARP requests. In all other cases, * allow the caller another chance at success next time. /* return B_TRUE if dropped */ /* sent on the cast_ill */ * broadcast an announce to ill_bcast address. /* return B_TRUE if dropped */ /* This is a module close */ * could not enter the ipsq because ill is already * Either we did not get an ill because it was marked CONDEMNED * or we could not enter the ipsq because it was unplumbing. * In both cases, wait for the ill to complete ip_modclose(). * If the arp_modclose happened even before SLIFNAME, the ai * itself would be NULL, in which case we can complete the close * If the ill had completed unplumbing before arp_modclose(), there * would be no ill (and therefore, no ipsq) to serialize arp_modclose() * so that we need to explicitly check for ARL_CONDEMNED and back off * send out all pending dlpi messages, don't wait for the ack (which * will be ignored in arp_rput when CONDEMNED is set) * We have to check for pending DL_UNBIND_REQ because, in the case * that ip_modclose() executed before arp_modclose(), the call to * ill_delete_tail->ipif_arp_down() would have triggered a * DL_UNBIND_REQ. When arp_modclose() executes ipsq_enter() will fail * (since ip_modclose() is in the ipsq) but the DL_UNBIND_ACK may not * have been processed yet. In this scenario, we cannot reset * related to unbind, and the associated cv_waits must be allowed to /* Wait for data paths to quiesce */ * unbind, so that nothing else can come up from driver. /* wait for unbind ack */ * credp could be null if the open didn't succeed and ip_modopen /* Free all retained control messages. */ * DAD failed. Tear down ipifs with the specified srce address. Note that * tearing down the ipif also meas deleting the ncec through ipif_down, * so it is not possible to use nce_timer for recovery. Instead we start * a timer on the ipif. Caller has to free the mp. * This is for exclusive changes due to ARP. Tear down an interface due * to AR_CN_FAILED and AR_CN_BOGON. /* first try src = ar$spa */ * Ignore conflicts generated by misbehaving switches that * just reflect our own messages back to us. For IPMP, we may * see reflections across any ill in the illgrp. /* For an under ill_grp can change under lock */ * Look up the appropriate ipif. /* Reload the ill to match the ipif */ /* If it's already duplicate or ineligible, then don't do anything. */ * If we failed on a recovery probe, then restart the timer to * This is a place for a dtrace hook. * Note that mp can be either the DL_UNITDATA_IND with a b_cont payload, * or just the ARP packet payload as an M_DATA. * check if first module below stream head is IP or UDP. * module below is not ip or udp, so arp has been pushed * In most cases we must be a writer on the IP stream before coming to * arp_dlpi_send(), to serialize DLPI sends to the driver. The exceptions * when we are not a writer are very early duing initialization (in * arl_init, before the arl has done a SLIFNAME, so that we don't yet know * the associated ill) or during arp_mod_close, when we could not enter the * ipsq because the ill has already unplumbed. /* Must queue message. Tail insertion */ * No need to take the arl_lock to examine ARL_CONDEMNED at this point * because the only thread that can see ARL_CONDEMNED here is the * closing arp_modclose() thread which sets the flag after becoming a * writer on the ipsq. Threads from IP must have finished and * Till the ill is fully up the ill is not globally visible. * allocate sufficient space to contain device name. /* Send down the Info Request to the driver. */ * Return value of 0 indicates a pending signal. * ip_rput_other could have set an error in ill_error on * Prevent unprivileged processes from pushing IP so that * they can't send raw IP. * For exclusive stacks we set the zoneid to zero * to make IP operate as if in the global zone. * Wait for the DL_INFO_ACK if a DL_INFO_REQ was sent. * Notify any downstream modules (esp softmac and hitbox) of the name * of this interface using an M_CTL. /* Use M_CTL to avoid confusing anyone else who might be listening. */ char *,
"SIOCSLIFNAME",
char *,
"-",
arl_t *,
arl);
* arl_got_replumb and arl_got_unbind to be cleared after we complete * The unplumb code paths call arp_unbind_complete() to make sure that it is * safe to tear down the ill. We wait for DL_UNBIND_ACK to complete, and also * for the arl_refcnt to fall to one so that, when we return from * arp_unbind_complete(), we know for certain that there are no threads in * arp_rput() that might access the arl_ill. * wait for unbind ack and arl_refcnt to drop to 1. Note that the * quiescent arl_refcnt for this function is 1 (and not 0) because * ill_to_arl() will itself return after taking a ref on the arl_t.