summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c')
-rw-r--r--usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c236
1 files changed, 77 insertions, 159 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c
index 27716cabce..703ddcfaad 100644
--- a/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c
+++ b/usr/src/cmd/cmd-inet/usr.lib/in.ndpd/main.c
@@ -17,14 +17,11 @@
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
- */
-/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ *
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include "defs.h"
#include "tables.h"
#include <fcntl.h>
@@ -122,7 +119,7 @@ sendpacket(struct sockaddr_in6 *sin6, int sock, int size, int flags)
char abuf[INET6_ADDRSTRLEN];
cc = sendto(sock, (char *)packet, size, flags,
- (struct sockaddr *)sin6, sizeof (*sin6));
+ (struct sockaddr *)sin6, sizeof (*sin6));
if (cc < 0 || cc != size) {
if (cc < 0) {
logperror("sendpacket: sendto");
@@ -135,6 +132,32 @@ sendpacket(struct sockaddr_in6 *sin6, int sock, int size, int flags)
}
}
+/*
+ * If possible, place an ND_OPT_SOURCE_LINKADDR option at `optp'.
+ * Return the number of bytes placed in the option.
+ */
+static uint_t
+add_opt_lla(struct phyint *pi, struct nd_opt_lla *optp)
+{
+ uint_t optlen;
+ uint_t hwaddrlen;
+ struct lifreq lifr;
+
+ /* If this phyint doesn't have a link-layer address, bail */
+ if (phyint_get_lla(pi, &lifr) == -1)
+ return (0);
+
+ hwaddrlen = lifr.lifr_nd.lnr_hdw_len;
+ /* roundup to multiple of 8 and make padding zero */
+ optlen = ((sizeof (struct nd_opt_hdr) + hwaddrlen + 7) / 8) * 8;
+ bzero(optp, optlen);
+ optp->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR;
+ optp->nd_opt_lla_len = optlen / 8;
+ bcopy(lifr.lifr_nd.lnr_hdw_addr, optp->nd_opt_lla_hdw_addr, hwaddrlen);
+
+ return (optlen);
+}
+
/* Send a Router Solicitation */
static void
solicit(struct sockaddr_in6 *sin6, struct phyint *pi)
@@ -151,24 +174,8 @@ solicit(struct sockaddr_in6 *sin6, struct phyint *pi)
packetlen += sizeof (*rs);
pptr += sizeof (*rs);
- /* Attach any options */
- if (pi->pi_hdw_addr_len != 0) {
- struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr;
- int optlen;
-
- /* roundup to multiple of 8 and make padding zero */
- optlen = ((sizeof (struct nd_opt_hdr) +
- pi->pi_hdw_addr_len + 7) / 8) * 8;
- bzero(pptr, optlen);
-
- lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR;
- lo->nd_opt_lla_len = optlen / 8;
- bcopy((char *)pi->pi_hdw_addr,
- (char *)lo->nd_opt_lla_hdw_addr,
- pi->pi_hdw_addr_len);
- packetlen += optlen;
- pptr += optlen;
- }
+ /* add options */
+ packetlen += add_opt_lla(pi, (struct nd_opt_lla *)pptr);
if (debug & D_PKTOUT) {
print_route_sol("Sending solicitation to ", pi, rs, packetlen,
@@ -224,24 +231,9 @@ advertise(struct sockaddr_in6 *sin6, struct phyint *pi, boolean_t no_prefixes)
return;
}
- /* Attach any options */
- if (pi->pi_hdw_addr_len != 0) {
- struct nd_opt_lla *lo = (struct nd_opt_lla *)pptr;
- int optlen;
-
- /* roundup to multiple of 8 and make padding zero */
- optlen = ((sizeof (struct nd_opt_hdr) +
- pi->pi_hdw_addr_len + 7) / 8) * 8;
- bzero(pptr, optlen);
-
- lo->nd_opt_lla_type = ND_OPT_SOURCE_LINKADDR;
- lo->nd_opt_lla_len = optlen / 8;
- bcopy((char *)pi->pi_hdw_addr,
- (char *)lo->nd_opt_lla_hdw_addr,
- pi->pi_hdw_addr_len);
- packetlen += optlen;
- pptr += optlen;
- }
+ /* add options */
+ packetlen += add_opt_lla(pi, (struct nd_opt_lla *)pptr);
+ pptr = (char *)packet + packetlen;
if (pi->pi_AdvLinkMTU != 0) {
struct nd_opt_mtu *mo = (struct nd_opt_mtu *)pptr;
@@ -1671,10 +1663,10 @@ process_rtsock(int rtsock)
return;
}
- if (ifm->ifm_flags != pi->pi_flags) {
+ if (ifm->ifm_flags != (uint_t)pi->pi_flags) {
if (debug & D_IFSCAN) {
logmsg(LOG_DEBUG, "process_rtsock: clr for "
- "%s old flags 0x%x new flags 0x%x\n",
+ "%s old flags 0x%llx new flags 0x%x\n",
pi->pi_name, pi->pi_flags, ifm->ifm_flags);
}
}
@@ -1825,141 +1817,67 @@ process_mibsock(int mibsock)
}
/*
- * Check whether the address formed by pr->pr_prefix and pi_token
- * exists in the kernel. Cannot call SIOCTMYADDR/ONLINK as it
- * does not check for down addresses. This function should not
- * be called for onlink prefixes.
- */
-static boolean_t
-is_address_present(struct phyint *pi, struct prefix *pr, uint64_t flags)
-{
- int s;
- in6_addr_t addr, *token;
- int i;
- int ret;
- struct sockaddr_in6 sin6;
-
- s = socket(AF_INET6, SOCK_DGRAM, 0);
- if (s < 0) {
- logperror("is_address_present: socket");
- /*
- * By returning B_TRUE, we make the caller delete
- * the prefix from the internal table. In the worst
- * case the next RA will create the prefix.
- */
- return (_B_TRUE);
- }
- if (flags & IFF_TEMPORARY)
- token = &pi->pi_tmp_token;
- else
- token = &pi->pi_token;
- for (i = 0; i < 16; i++) {
- /*
- * prefix_create ensures that pr_prefix has all-zero
- * bits after prefixlen.
- */
- addr.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i];
- }
- (void) memset(&sin6, 0, sizeof (struct sockaddr_in6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_addr = addr;
- ret = bind(s, (struct sockaddr *)&sin6, sizeof (struct sockaddr_in6));
- (void) close(s);
- if (ret < 0 && errno == EADDRNOTAVAIL)
- return (_B_FALSE);
- else
- return (_B_TRUE);
-}
-
-/*
* Look if the phyint or one of its prefixes have been removed from
* the kernel and take appropriate action.
- * Uses {pi,pr}_in_use.
+ * Uses pr_in_use and pi{,_kernel}_state.
*/
static void
check_if_removed(struct phyint *pi)
{
- struct prefix *pr;
- struct prefix *next_pr;
+ struct prefix *pr, *next_pr;
/*
- * Detect phyints that have been removed from the kernel.
- * Since we can't recreate it here (would require ifconfig plumb
- * logic) we just terminate use of that phyint.
- */
- if (!(pi->pi_kernel_state & PI_PRESENT) &&
- (pi->pi_state & PI_PRESENT)) {
- logmsg(LOG_ERR, "Interface %s has been removed from kernel. "
- "in.ndpd will no longer use it\n", pi->pi_name);
- /*
- * Clear state so that should the phyint reappear
- * we will start with initial advertisements or
- * solicitations.
- */
- phyint_cleanup(pi);
- }
- /*
* Detect prefixes which are removed.
- *
- * We remove the prefix in all of the following cases :
- *
- * 1) Static prefixes are not the ones we create. So,
- * just remove it from our tables.
- *
- * 2) On-link prefixes potentially move to a different
- * phyint during failover. As it does not have
- * an address, we can't use the logic in is_address_present
- * to detect whether it is present in the kernel or not.
- * Thus when it is manually removed we don't recreate it.
- *
- * 3) If there is a token mis-match and this prefix is not
- * in the kernel, it means we don't need this prefix on
- * this interface anymore. It must have been moved to a
- * different interface by in.mpathd. This normally
- * happens after a failover followed by a failback (or
- * another failover) and we re-read the network
- * configuration. For the failover from A to B, we would
- * have created state on B about A's address, which will
- * not be in use after the subsequent failback. So, we
- * remove that prefix here.
- *
- * 4) If the physical interface is not present, then remove
- * the prefix. In the cases where we are advertising
- * prefixes, the state is kept in advertisement prefix and
- * hence we can delete the prefix.
- *
- * 5) Similar to case (3), when we failover from A to B, the
- * prefix in A will not be in use as it has been moved to B.
- * We will delete it from our tables and recreate it when
- * it fails back. is_address_present makes sure that the
- * address is still valid in kernel.
- *
- * If none of the above is true, we recreate the prefix as it
- * has been manually removed. We do it only when the interface
- * is not FAILED or INACTIVE or OFFLINE.
+ * Static prefixes are just removed from our tables.
+ * Non-static prefixes are recreated i.e. in.ndpd takes precedence
+ * over manually removing prefixes via ifconfig.
*/
for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) {
next_pr = pr->pr_next;
if (!pr->pr_in_use) {
- /* Clear PR_AUTO and PR_ONLINK */
+ /* Clear everything except PR_STATIC */
pr->pr_kernel_state &= PR_STATIC;
- if ((pr->pr_state & PR_STATIC) ||
- !(pr->pr_state & PR_AUTO) ||
- !(prefix_token_match(pi, pr, pr->pr_flags)) ||
- (!(pi->pi_kernel_state & PI_PRESENT)) ||
- (is_address_present(pi, pr, pr->pr_flags))) {
+ pr->pr_name[0] = '\0';
+ if (pr->pr_state & PR_STATIC) {
prefix_delete(pr);
- } else if (!(pi->pi_flags &
- (IFF_FAILED|IFF_INACTIVE|IFF_OFFLINE)) &&
- pr->pr_state != pr->pr_kernel_state) {
- pr->pr_name[0] = '\0';
+ } else if (!(pi->pi_kernel_state & PI_PRESENT)) {
+ /*
+ * Ensure that there are no future attempts to
+ * run prefix_update_k since the phyint is gone.
+ */
+ pr->pr_state = pr->pr_kernel_state;
+ } else if (pr->pr_state != pr->pr_kernel_state) {
logmsg(LOG_INFO, "Prefix manually removed "
- "on %s - recreating it!\n",
- pi->pi_name);
+ "on %s; recreating\n", pi->pi_name);
prefix_update_k(pr);
}
}
}
+
+ /*
+ * Detect phyints that have been removed from the kernel, and tear
+ * down any prefixes we created that are associated with that phyint.
+ * (NOTE: IPMP depends on in.ndpd tearing down these prefixes so an
+ * administrator can easily place an IP interface with ADDRCONF'd
+ * addresses into an IPMP group.)
+ */
+ if (!(pi->pi_kernel_state & PI_PRESENT) &&
+ (pi->pi_state & PI_PRESENT)) {
+ logmsg(LOG_ERR, "Interface %s has been removed from kernel. "
+ "in.ndpd will no longer use it\n", pi->pi_name);
+
+ for (pr = pi->pi_prefix_list; pr != NULL; pr = next_pr) {
+ next_pr = pr->pr_next;
+ if (pr->pr_state & PR_AUTO)
+ prefix_delete(pr);
+ }
+
+ /*
+ * Clear state so that should the phyint reappear we will
+ * start with initial advertisements or solicitations.
+ */
+ phyint_cleanup(pi);
+ }
}