From owner-svn-src-projects@freebsd.org Tue Nov 22 09:52:34 2016 Return-Path: Delivered-To: svn-src-projects@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B8850C4FC54 for ; Tue, 22 Nov 2016 09:52:34 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 9592A871; Tue, 22 Nov 2016 09:52:34 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id uAM9qXPe066750; Tue, 22 Nov 2016 09:52:33 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id uAM9qXPc066749; Tue, 22 Nov 2016 09:52:33 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201611220952.uAM9qXPc066749@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Tue, 22 Nov 2016 09:52:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r308968 - projects/ipsec/sys/netipsec X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Nov 2016 09:52:34 -0000 Author: ae Date: Tue Nov 22 09:52:33 2016 New Revision: 308968 URL: https://svnweb.freebsd.org/changeset/base/308968 Log: Rework key_allocsa_policy() function. Remove old code used for allocating SA for outbound packet. Now only key_allocsa_policy() function will be used for this. As arguments it takes security policy that was found by ipsec[46]_checkpolicy() and secasindex constructed using information from policy and mbuf. Using secasindex we do lookup in SAH hash table, then based on key_preferred_oldsa variable we take LAST or FIRST element from SAH's savtree_alive. If correspondig SAH entry was not found, we acquire SA from IKEd using key_acquire() function. Modified: projects/ipsec/sys/netipsec/key.c Modified: projects/ipsec/sys/netipsec/key.c ============================================================================== --- projects/ipsec/sys/netipsec/key.c Tue Nov 22 09:49:15 2016 (r308967) +++ projects/ipsec/sys/netipsec/key.c Tue Nov 22 09:52:33 2016 (r308968) @@ -784,265 +784,75 @@ key_allocsp(struct secpolicyindex *spidx } /* - * allocating an SA entry for an *OUTBOUND* packet. - * checking each request entries in SP, and acquire an SA if need. - * OUT: 0: there are valid requests. - * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. + * Allocating an SA entry for an *OUTBOUND* packet. + * OUT: positive: corresponding SA for given saidx found. + * NULL: SA not found, but will be acquired, check *error + * for acquiring status. */ -int -key_checkrequest(struct ipsecrequest *isr, const struct secasindex *saidx) +struct secasvar * +key_allocsa_policy(struct secpolicy *sp, const struct secasindex *saidx, + int *error) { - u_int level; - int error; + SAHTREE_RLOCK_TRACKER; + struct secashead *sah; struct secasvar *sav; - IPSEC_ASSERT(isr != NULL, ("null isr")); IPSEC_ASSERT(saidx != NULL, ("null saidx")); IPSEC_ASSERT(saidx->mode == IPSEC_MODE_TRANSPORT || saidx->mode == IPSEC_MODE_TUNNEL, ("unexpected policy %u", saidx->mode)); /* - * XXX guard against protocol callbacks from the crypto - * thread as they reference ipsecrequest.sav which we - * temporarily null out below. Need to rethink how we - * handle bundled SA's in the callback thread. - */ - IPSECREQUEST_LOCK_ASSERT(isr); - - /* get current level */ - level = ipsec_get_reqlevel(isr); - - /* * We check new SA in the IPsec request because a different * SA may be involved each time this request is checked, either * because new SAs are being configured, or this request is * associated with an unconnected datagram socket, or this request * is associated with a system default policy. - * - * key_allocsa_policy should allocate the oldest SA available. - * See key_do_allocsa_policy(), and draft-jenkins-ipsec-rekeying-03.txt. */ - sav = key_allocsa_policy(saidx); - if (sav != isr->sav) { - /* SA need to be updated. */ - if (!IPSECREQUEST_UPGRADE(isr)) { - /* Kick everyone off. */ - IPSECREQUEST_UNLOCK(isr); - IPSECREQUEST_WLOCK(isr); - } - if (isr->sav != NULL) - KEY_FREESAV(&isr->sav); - isr->sav = sav; - IPSECREQUEST_DOWNGRADE(isr); - } else if (sav != NULL) - KEY_FREESAV(&sav); - - /* When there is SA. */ - if (isr->sav != NULL) { - if (isr->sav->state != SADB_SASTATE_MATURE && - isr->sav->state != SADB_SASTATE_DYING) - return EINVAL; - return 0; - } - - /* there is no SA */ - error = key_acquire(saidx, isr->sp); - if (error != 0) { - /* XXX What should I do ? */ - ipseclog((LOG_DEBUG, "%s: error %d returned from key_acquire\n", - __func__, error)); - return error; - } - - if (level != IPSEC_LEVEL_REQUIRE) { - /* XXX sigh, the interface to this routine is botched */ - IPSEC_ASSERT(isr->sav == NULL, ("unexpected SA")); - return 0; - } else { - return ENOENT; - } -} - -/* - * allocating a SA for policy entry from SAD. - * NOTE: searching SAD of aliving state. - * OUT: NULL: not found. - * others: found and return the pointer. - */ -static struct secasvar * -key_allocsa_policy(const struct secasindex *saidx) -{ -#define N(a) _ARRAYLEN(a) - struct secashead *sah; - struct secasvar *sav; - u_int stateidx, arraysize; - const u_int *state_valid; - - state_valid = NULL; /* silence gcc */ - arraysize = 0; /* silence gcc */ - - SAHTREE_LOCK(); - LIST_FOREACH(sah, &V_sahtree, chain) { - if (sah->state == SADB_SASTATE_DEAD) - continue; - if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) { - if (V_key_preferred_oldsa) { - state_valid = saorder_state_valid_prefer_old; - arraysize = N(saorder_state_valid_prefer_old); - } else { - state_valid = saorder_state_valid_prefer_new; - arraysize = N(saorder_state_valid_prefer_new); - } + SAHTREE_RLOCK(); + LIST_FOREACH(sah, SAHADDRHASH_HASH(saidx), addrhash) { + KEYDBG(IPSEC_DUMP, + printf("%s: checking SAH\n", __func__); + kdebug_secash(sah, " ")); + if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) break; - } - } - SAHTREE_UNLOCK(); - if (sah == NULL) - return NULL; - /* search valid state */ - for (stateidx = 0; stateidx < arraysize; stateidx++) { - sav = key_do_allocsa_policy(sah, state_valid[stateidx]); - if (sav != NULL) - return sav; } - - return NULL; -#undef N -} - -/* - * searching SAD with direction, protocol, mode and state. - * called by key_allocsa_policy(). - * OUT: - * NULL : not found - * others : found, pointer to a SA. - */ -static struct secasvar * -key_do_allocsa_policy(struct secashead *sah, u_int state) -{ - struct secasvar *sav, *nextsav, *candidate, *d; - - /* initialize */ - candidate = NULL; - - SAHTREE_LOCK(); - for (sav = LIST_FIRST(&sah->savtree[state]); - sav != NULL; - sav = nextsav) { - - nextsav = LIST_NEXT(sav, chain); - - /* sanity check */ - KEY_CHKSASTATE(sav->state, state, __func__); - - /* initialize */ - if (candidate == NULL) { - candidate = sav; - continue; - } - - /* Which SA is the better ? */ - - IPSEC_ASSERT(candidate->lft_c != NULL, - ("null candidate lifetime")); - IPSEC_ASSERT(sav->lft_c != NULL, ("null sav lifetime")); - - /* What the best method is to compare ? */ - if (V_key_preferred_oldsa) { - if (candidate->lft_c->addtime > - sav->lft_c->addtime) { - candidate = sav; - } - continue; - /*NOTREACHED*/ - } - - /* preferred new sa rather than old sa */ - if (candidate->lft_c->addtime < - sav->lft_c->addtime) { - d = candidate; - candidate = sav; - } else - d = sav; - + if (sah != NULL) { /* - * prepared to delete the SA when there is more - * suitable candidate and the lifetime of the SA is not - * permanent. + * Allocate the oldest SA available according to + * draft-jenkins-ipsec-rekeying-03. */ - if (d->lft_h->addtime != 0) { - struct mbuf *m, *result; - u_int8_t satype; - - key_sa_chgstate(d, SADB_SASTATE_DEAD); - - IPSEC_ASSERT(d->refcnt > 0, ("bogus ref count")); - - satype = key_proto2satype(d->sah->saidx.proto); - if (satype == 0) - goto msgfail; - - m = key_setsadbmsg(SADB_DELETE, 0, - satype, 0, 0, d->refcnt - 1); - if (!m) - goto msgfail; - result = m; - - /* set sadb_address for saidx's. */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_SRC, - &d->sah->saidx.src.sa, - d->sah->saidx.src.sa.sa_len << 3, - IPSEC_ULPROTO_ANY); - if (!m) - goto msgfail; - m_cat(result, m); - - /* set sadb_address for saidx's. */ - m = key_setsadbaddr(SADB_EXT_ADDRESS_DST, - &d->sah->saidx.dst.sa, - d->sah->saidx.dst.sa.sa_len << 3, - IPSEC_ULPROTO_ANY); - if (!m) - goto msgfail; - m_cat(result, m); - - /* create SA extension */ - m = key_setsadbsa(d); - if (!m) - goto msgfail; - m_cat(result, m); + if (V_key_preferred_oldsa) + sav = TAILQ_LAST(&sah->savtree_alive, secasvar_queue); + else + sav = TAILQ_FIRST(&sah->savtree_alive); + if (sav != NULL) + SAV_ADDREF(sav); + } else + sav = NULL; + SAHTREE_RUNLOCK(); - if (result->m_len < sizeof(struct sadb_msg)) { - result = m_pullup(result, - sizeof(struct sadb_msg)); - if (result == NULL) - goto msgfail; - } - - result->m_pkthdr.len = 0; - for (m = result; m; m = m->m_next) - result->m_pkthdr.len += m->m_len; - mtod(result, struct sadb_msg *)->sadb_msg_len = - PFKEY_UNIT64(result->m_pkthdr.len); - - if (key_sendup_mbuf(NULL, result, - KEY_SENDUP_REGISTERED)) - goto msgfail; - msgfail: - KEY_FREESAV(&d); - } - } - if (candidate) { - sa_addref(candidate); - KEYDEBUG(KEYDEBUG_IPSEC_STAMP, - printf("DP %s cause refcnt++:%d SA:%p\n", - __func__, candidate->refcnt, candidate)); + if (sav != NULL) { + *error = 0; + KEYDBG(IPSEC_STAMP, + printf("%s: chosen SA(%p) for SP(%p)\n", __func__, + sav, sp)); + KEYDBG(IPSEC_DATA, kdebug_secasv(sav)); + return (sav); /* return referenced SA */ } - SAHTREE_UNLOCK(); - return candidate; + /* there is no SA */ + *error = key_acquire(saidx, sp); + if ((*error) != 0) + ipseclog((LOG_DEBUG, + "%s: error %d returned from key_acquire()\n", + __func__, *error)); + KEYDBG(IPSEC_STAMP, + printf("%s: acquire SA for SP(%p), error %d\n", + __func__, sp, *error)); + KEYDBG(IPSEC_DATA, kdebug_secasindex(saidx, NULL)); + return (NULL); } /*