Enter and exit the network epoch for async IPsec callbacks.

When an IPsec packet has been encrypted or decrypted, the next step in
the packet's traversal through the network stack is invoked from a
crypto worker thread, not from the original calling thread.  These
threads need to enter the network epoch before passing packets down to
IP output routines or up to transport protocols.

Reviewed by:	ae
Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D25444
This commit is contained in:
John Baldwin 2020-06-25 23:57:30 +00:00
parent 9b934d4360
commit f82eb2a6f0
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=362635
2 changed files with 23 additions and 6 deletions

View File

@ -278,6 +278,7 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
int protoff)
{
IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
struct epoch_tracker et;
struct ipsec_ctx_data ctx;
struct xform_history *xh;
struct secasindex *saidx;
@ -424,7 +425,9 @@ ipsec4_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
if (saidx->mode == IPSEC_MODE_TUNNEL)
error = ipsec_if_input(m, sav, af);
if (error == 0) {
NET_EPOCH_ENTER(et);
error = netisr_queue_src(isr_prot, (uintptr_t)sav->spi, m);
NET_EPOCH_EXIT(et);
if (error) {
IPSEC_ISTAT(sproto, qfull);
DPRINTF(("%s: queue full; proto %u packet dropped\n",
@ -489,6 +492,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
int protoff)
{
IPSEC_DEBUG_DECLARE(char buf[IPSEC_ADDRSTRLEN]);
struct epoch_tracker et;
struct ipsec_ctx_data ctx;
struct xform_history *xh;
struct secasindex *saidx;
@ -621,8 +625,10 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
if (saidx->mode == IPSEC_MODE_TUNNEL)
error = ipsec_if_input(m, sav, af);
if (error == 0) {
NET_EPOCH_ENTER(et);
error = netisr_queue_src(isr_prot,
(uintptr_t)sav->spi, m);
NET_EPOCH_EXIT(et);
if (error) {
IPSEC_ISTAT(sproto, qfull);
DPRINTF(("%s: queue full; proto %u packet"
@ -638,11 +644,12 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
*/
nest = 0;
nxt = nxt8;
NET_EPOCH_ENTER(et);
while (nxt != IPPROTO_DONE) {
if (V_ip6_hdrnestlimit && (++nest > V_ip6_hdrnestlimit)) {
IP6STAT_INC(ip6s_toomanyhdr);
error = EINVAL;
goto bad;
goto bad_epoch;
}
/*
@ -653,7 +660,7 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
IP6STAT_INC(ip6s_tooshort);
in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated);
error = EINVAL;
goto bad;
goto bad_epoch;
}
/*
* Enforce IPsec policy checking if we are seeing last header.
@ -663,12 +670,15 @@ ipsec6_common_input_cb(struct mbuf *m, struct secasvar *sav, int skip,
if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 &&
ipsec6_in_reject(m, NULL)) {
error = EINVAL;
goto bad;
goto bad_epoch;
}
nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &skip, nxt);
}
NET_EPOCH_EXIT(et);
key_freesav(&sav);
return (0);
bad_epoch:
NET_EPOCH_EXIT(et);
bad:
key_freesav(&sav);
if (m)

View File

@ -688,6 +688,7 @@ int
ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
u_int idx)
{
struct epoch_tracker et;
struct xform_history *xh;
struct secasindex *saidx;
struct m_tag *mtag;
@ -789,19 +790,25 @@ ipsec_process_done(struct mbuf *m, struct secpolicy *sp, struct secasvar *sav,
* We're done with IPsec processing, transmit the packet using the
* appropriate network protocol (IP or IPv6).
*/
NET_EPOCH_ENTER(et);
switch (saidx->dst.sa.sa_family) {
#ifdef INET
case AF_INET:
key_freesav(&sav);
return ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
error = ip_output(m, NULL, NULL, IP_RAWOUTPUT, NULL, NULL);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
key_freesav(&sav);
return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
break;
#endif /* INET6 */
default:
panic("ipsec_process_done");
}
panic("ipsec_process_done");
NET_EPOCH_EXIT(et);
return (error);
bad:
m_freem(m);
key_freesav(&sav);