# HG changeset patch # User narayan # Date 1171510327 28800 # Node ID b023d36e83d96fa863d0b670e76911107a207161 # Parent fe555d5eb825d95bb9315bbfc527e2bec9400b1d 6512526 RC1a: vntsd needs to validate the listen-to IP address 6512604 handshake untimeout() race condition in vnet 6517019 vgen_multicst does not handle kmem_zalloc failure 6520018 vntsd gets confused and immediately closes newly established console connections 6521890 recursive mutex_enter in ldc_set_cb_mode diff -r fe555d5eb825 -r b023d36e83d9 usr/src/cmd/vntsd/listen.c --- a/usr/src/cmd/vntsd/listen.c Wed Feb 14 19:20:08 2007 -0800 +++ b/usr/src/cmd/vntsd/listen.c Wed Feb 14 19:32:07 2007 -0800 @@ -45,6 +45,7 @@ #include "vntsd.h" #define MAX_BIND_RETRIES 6 + /* * check the state of listen thread. exit if there is an fatal error * or the group is removed. Main thread will call free_group @@ -70,22 +71,13 @@ case VNTSD_SUCCESS: return; - case VNTSD_STATUS_INTR: - /* signal for deleting group */ - assert(groupp->status & VNTSD_GROUP_SIG_WAIT); - - /* let main thread know */ - (void) mutex_lock(&groupp->lock); - groupp->status &= ~VNTSD_GROUP_SIG_WAIT; - (void) cond_signal(&groupp->cvp); - (void) mutex_unlock(&groupp->lock); - - thr_exit(0); - break; case VNTSD_STATUS_ACCEPT_ERR: return; + case VNTSD_STATUS_INTR: + assert(groupp->status & VNTSD_GROUP_SIG_WAIT); + /*FALLTHRU*/ case VNTSD_STATUS_NO_CONS: default: /* fatal error or no console in the group, remove the group. */ @@ -93,9 +85,14 @@ (void) mutex_lock(&groupp->lock); if (groupp->status & VNTSD_GROUP_SIG_WAIT) { - /* group is already in deletion */ + /* + * group is already being deleted, notify main + * thread and exit. + */ + groupp->status &= ~VNTSD_GROUP_SIG_WAIT; + (void) cond_signal(&groupp->cvp); (void) mutex_unlock(&groupp->lock); - return; + thr_exit(0); } /* @@ -115,7 +112,7 @@ /* log error */ if (status != VNTSD_STATUS_NO_CONS) vntsd_log(status, err_msg); - break; + thr_exit(0); } } diff -r fe555d5eb825 -r b023d36e83d9 usr/src/cmd/vntsd/vntsd.c --- a/usr/src/cmd/vntsd/vntsd.c Wed Feb 14 19:20:08 2007 -0800 +++ b/usr/src/cmd/vntsd/vntsd.c Wed Feb 14 19:32:07 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -56,6 +56,8 @@ #include #include #include +#include +#include #include "vntsd.h" #include "chars.h" @@ -71,6 +73,8 @@ #define MINUTE 60 +#define VNTSD_INVALID_LISTEN_ADDR ((in_addr_t)-1) + static vntsd_t *vntsdp; @@ -259,6 +263,57 @@ "[-p ] [-t ]\n")); } +/* + * get_listen_ip_addr() + * check for a valid control domain ip address in format of xxx.xxx.xxx.xxx. + * if ip address is valid and is assigned to this host, return ip address + * or else return VNTSD_INVALID_LISTEN_ADDR. + */ +static in_addr_t +get_listen_ip_addr(char *listen_addr) +{ + char host_name[MAXPATHLEN]; + in_addr_t addr; + struct addrinfo hints; + struct addrinfo *res, *infop; + int err; + struct sockaddr_in *sa; + + if (gethostname(host_name, MAXPATHLEN) != 0) { + syslog(LOG_ERR, "Can not get host name!"); + return (VNTSD_INVALID_LISTEN_ADDR); + } + + if ((int)(addr = inet_addr(listen_addr)) == -1) + /* bad IP address format */ + return (VNTSD_INVALID_LISTEN_ADDR); + + bzero(&hints, sizeof (hints)); + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + + err = getaddrinfo(host_name, NULL, &hints, &res); + if (err != 0) { + syslog(LOG_ERR, "getaddrinfo failed: %s", gai_strerror(err)); + return (VNTSD_INVALID_LISTEN_ADDR); + } + + infop = res; + while (infop != NULL) { + /* LINTED E_BAD_PTR_CAST_ALIGN */ + sa = (struct sockaddr_in *)infop->ai_addr; + if (sa->sin_addr.s_addr == addr) { + /* ip address found */ + freeaddrinfo(res); + return (addr); + } + infop = infop->ai_next; + } + + /* ip address not found */ + freeaddrinfo(res); + return (VNTSD_INVALID_LISTEN_ADDR); +} #ifdef DEBUG #define DEBUG_OPTIONS "d" @@ -340,12 +395,12 @@ } else if (strcmp(listen_addr, "any") == 0) { vntsdp->ip_addr.s_addr = htonl(INADDR_ANY); } else { - vntsdp->ip_addr.s_addr = inet_addr(listen_addr); - if (vntsdp->ip_addr.s_addr == (in_addr_t)(-1)) { - (void) fprintf(stderr, - gettext("Invalid listen address '%s'\n"), + vntsdp->ip_addr.s_addr = get_listen_ip_addr(listen_addr); + if (vntsdp->ip_addr.s_addr == VNTSD_INVALID_LISTEN_ADDR) { + syslog(LOG_ERR, + "Invalid listen address '%s'\n", listen_addr); - exit(1); + exit(2); } } diff -r fe555d5eb825 -r b023d36e83d9 usr/src/uts/sun4v/io/ldc.c --- a/usr/src/uts/sun4v/io/ldc.c Wed Feb 14 19:20:08 2007 -0800 +++ b/usr/src/uts/sun4v/io/ldc.c Wed Feb 14 19:32:07 2007 -0800 @@ -3232,6 +3232,7 @@ mutex_enter(&ldcp->tx_lock); i_ldc_reset(ldcp, B_TRUE); mutex_exit(&ldcp->tx_lock); + mutex_exit(&ldcp->lock); return (ECONNRESET); } diff -r fe555d5eb825 -r b023d36e83d9 usr/src/uts/sun4v/io/vnet_gen.c --- a/usr/src/uts/sun4v/io/vnet_gen.c Wed Feb 14 19:20:08 2007 -0800 +++ b/usr/src/uts/sun4v/io/vnet_gen.c Wed Feb 14 19:32:07 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -773,7 +773,7 @@ vgen_ldclist_t *ldclp; void *vnetp; struct ether_addr *addrp; - int rv; + int rv = DDI_FAILURE; uint32_t i; vgenp = (vgen_t *)arg; @@ -791,18 +791,16 @@ portp = vgenp->vsw_portp; if (portp == NULL) { RW_EXIT(&plistp->rwlock); - goto vgen_mcast_exit; + mutex_exit(&vgenp->lock); + return (rv); } ldclp = &portp->ldclist; READ_ENTER(&ldclp->rwlock); ldcp = ldclp->headp; - if (ldcp == NULL) { - RW_EXIT(&ldclp->rwlock); - RW_EXIT(&plistp->rwlock); + if (ldcp == NULL) goto vgen_mcast_exit; - } mutex_enter(&ldcp->cblock); @@ -818,11 +816,12 @@ bcopy(mca, &(mcastmsg.mca), ETHERADDRL); mcastmsg.set = add; mcastmsg.count = 1; - rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), - B_FALSE); - if (rv != VGEN_SUCCESS) { + if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), + B_FALSE) != VGEN_SUCCESS) { DWARN((vnetp, "vgen_mutlicst: vgen_sendmsg failed" "id (%lx)\n", ldcp->ldc_id)); + mutex_exit(&ldcp->cblock); + goto vgen_mcast_exit; } } else { /* set the flag to send a msg to vsw after handshake is done */ @@ -843,7 +842,8 @@ newtab = kmem_zalloc(newsize * sizeof (struct ether_addr), KM_NOSLEEP); - + if (newtab == NULL) + goto vgen_mcast_exit; bcopy(vgenp->mctab, newtab, vgenp->mcsize * sizeof (struct ether_addr)); kmem_free(vgenp->mctab, @@ -878,12 +878,14 @@ } } + rv = DDI_SUCCESS; + +vgen_mcast_exit: RW_EXIT(&ldclp->rwlock); RW_EXIT(&plistp->rwlock); -vgen_mcast_exit: mutex_exit(&vgenp->lock); - return (DDI_SUCCESS); + return (rv); } /* set or clear promiscuous mode on the device */ @@ -1965,20 +1967,32 @@ "ldc_set_cb_mode failed\n", ldcp->ldc_id)); } - /* clear handshake done bit and wait for pending tx and cb to finish */ + /* + * clear handshake done bit and wait for pending tx and cb to finish. + * release locks before untimeout(9F) is invoked to cancel timeouts. + */ ldcp->hphase &= ~(VH_DONE); LDC_UNLOCK(ldcp); - drv_usecwait(1000); - LDC_LOCK(ldcp); - - vgen_reset_hphase(ldcp); - - /* reset transmit watchdog timeout */ + + /* cancel handshake watchdog timeout */ + if (ldcp->htid) { + (void) untimeout(ldcp->htid); + ldcp->htid = 0; + } + + /* cancel transmit watchdog timeout */ if (ldcp->wd_tid) { (void) untimeout(ldcp->wd_tid); ldcp->wd_tid = 0; } + drv_usecwait(1000); + + /* acquire locks again; any pending transmits and callbacks are done */ + LDC_LOCK(ldcp); + + vgen_reset_hphase(ldcp); + vgen_uninit_tbufs(ldcp); rv = ldc_close(ldcp->ldc_handle); @@ -2512,7 +2526,7 @@ } mutex_exit(&ldcp->cblock); - return (LDC_SUCCESS); + goto vgen_ldccb_exit; vgen_ldccb_rcv: @@ -2526,7 +2540,7 @@ "vgen_ldc_cb:ldc_read err id(%lx) rv(%d) " "len(%d)\n", ldcp->ldc_id, rv, msglen)); if (rv == ECONNRESET) - goto exit_error; + goto vgen_ldccb_error; break; } if (msglen == 0) { @@ -2558,7 +2572,7 @@ * reset the channel. */ ldcp->need_ldc_reset = B_TRUE; - goto exit_error; + goto vgen_ldccb_error; } } @@ -2593,7 +2607,7 @@ break; } -exit_error: +vgen_ldccb_error: if (rv == ECONNRESET) { if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { DWARN((vnetp, @@ -2621,6 +2635,20 @@ ldcp->ldc_id, MBLKL(mp))); vnet_rx(vgenp->vnetp, NULL, mp); } + +vgen_ldccb_exit: + if (ldcp->cancel_htid) { + /* + * Cancel handshake timer. + * untimeout(9F) will not return until the pending callback is + * cancelled or has run. No problems will result from calling + * untimeout if the handler has already completed. + * If the timeout handler did run, then it would just + * return as cancel_htid is set. + */ + (void) untimeout(ldcp->cancel_htid); + ldcp->cancel_htid = 0; + } DBG1((vnetp, "vgen_ldc_cb exit: ldcid (%lx)\n", ldcp->ldc_id)); return (LDC_SUCCESS); @@ -3055,9 +3083,13 @@ ldcp->hstate = 0; ldcp->hphase = VH_PHASE0; - /* reset handshake watchdog timeout */ + /* + * Save the id of pending handshake timer in cancel_htid. + * This will be checked in vgen_ldc_cb() and the handshake timer will + * be cancelled after releasing cblock. + */ if (ldcp->htid) { - (void) untimeout(ldcp->htid); + ldcp->cancel_htid = ldcp->htid; ldcp->htid = 0; } @@ -3149,13 +3181,6 @@ } else { ldcp->ldc_status = istatus; } - - /* if channel is already UP - restart handshake */ - if (istatus == LDC_UP) { - /* Initialize local session id */ - ldcp->local_sid = ddi_get_lbolt(); - vgen_handshake(vh_nextphase(ldcp)); - } } } @@ -3214,9 +3239,13 @@ break; case VH_DONE: - /* reset handshake watchdog timeout */ + /* + * Save the id of pending handshake timer in cancel_htid. + * This will be checked in vgen_ldc_cb() and the handshake + * timer will be cancelled after releasing cblock. + */ if (ldcp->htid) { - (void) untimeout(ldcp->htid); + ldcp->cancel_htid = ldcp->htid; ldcp->htid = 0; } ldcp->hretries = 0; @@ -3329,9 +3358,13 @@ { /* reset handshake phase */ vgen_handshake_reset(ldcp); - if (vgen_max_hretries) { /* handshake retry is specified */ - if (ldcp->hretries++ < vgen_max_hretries) + + /* handshake retry is specified and the channel is UP */ + if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) { + if (ldcp->hretries++ < vgen_max_hretries) { + ldcp->local_sid = ddi_get_lbolt(); vgen_handshake(vh_nextphase(ldcp)); + } } } @@ -4850,7 +4883,7 @@ #endif mutex_enter(&ldcp->cblock); ldcp->need_ldc_reset = B_TRUE; - vgen_handshake_reset(ldcp); + vgen_handshake_retry(ldcp); mutex_exit(&ldcp->cblock); if (ldcp->need_resched) { ldcp->need_resched = B_FALSE; @@ -5112,6 +5145,11 @@ ldcp->ldc_id, ldcp->hphase, ldcp->hstate)); mutex_enter(&ldcp->cblock); + if (ldcp->cancel_htid) { + ldcp->cancel_htid = 0; + mutex_exit(&ldcp->cblock); + return; + } ldcp->htid = 0; ldcp->need_ldc_reset = B_TRUE; vgen_handshake_retry(ldcp); diff -r fe555d5eb825 -r b023d36e83d9 usr/src/uts/sun4v/sys/vnet_gen.h --- a/usr/src/uts/sun4v/sys/vnet_gen.h Wed Feb 14 19:20:08 2007 -0800 +++ b/usr/src/uts/sun4v/sys/vnet_gen.h Wed Feb 14 19:32:07 2007 -0800 @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -247,6 +247,7 @@ vgen_hparams_t local_hparams; /* local handshake params */ vgen_hparams_t peer_hparams; /* peer's handshake params */ timeout_id_t htid; /* handshake wd timeout id */ + timeout_id_t cancel_htid; /* cancel handshake watchdog */ /* transmit and receive descriptor ring info */ ldc_dring_handle_t tx_dhandle; /* tx descriptor ring handle */