On 16/04/16(Sat) 18:41, Markus Friedl wrote: > Hi, this matches the IPsec/IPv4 change I committed back in December, but > since I don't have extensive IPv6 setups it's still not committed. Please > test, give feedback and it will finally go into the next release.
I hope it will go before the next release! This would help me a lot to turn the IPv6 forwarding path mpsafe. ok mpi@ >Index: netinet6/ip6_forward.c >=================================================================== >RCS file: /cvs/src/sys/netinet6/ip6_forward.c,v >retrieving revision 1.87 >diff -u -p -u -r1.87 ip6_forward.c >--- netinet6/ip6_forward.c 29 Mar 2016 11:57:51 -0000 1.87 >+++ netinet6/ip6_forward.c 13 Apr 2016 21:47:09 -0000 >@@ -93,15 +93,7 @@ ip6_forward(struct mbuf *m, int srcrt) > int error = 0, type = 0, code = 0; > struct mbuf *mcopy = NULL; > #ifdef IPSEC >- u_int8_t sproto = 0; >- struct m_tag *mtag; >- union sockaddr_union sdst; >- struct tdb_ident *tdbi; >- u_int32_t sspi; >- struct tdb *tdb; >-#if NPF > 0 >- struct ifnet *encif; >-#endif >+ struct tdb *tdb = NULL; > #endif /* IPSEC */ > u_int rtableid = 0; > char src6[INET6_ADDRSTRLEN], dst6[INET6_ADDRSTRLEN]; >@@ -155,64 +147,21 @@ reroute: > #endif > > #ifdef IPSEC >- if (!ipsec_in_use) >- goto done_spd; >- >- /* >- * Check if there was an outgoing SA bound to the flow >- * from a transport protocol. >- */ >- >- /* Do we have any pending SAs to apply ? */ >- tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr), >- &error, IPSP_DIRECTION_OUT, NULL, NULL, 0); >- >- if (tdb == NULL) { >- if (error == 0) { >- /* >- * No IPsec processing required, we'll just send the >- * packet out. >- */ >- sproto = 0; >- >- /* Fall through to routing/multicast handling */ >- } else { >- /* >+ if (ipsec_in_use) { >+ tdb = ip6_output_ipsec_lookup(m, &error, NULL); >+ if (error != 0) { >+ /* > * -EINVAL is used to indicate that the packet should > * be silently dropped, typically because we've asked > * key management for an SA. > */ >- if (error == -EINVAL) /* Should silently drop packet */ >+ if (error == -EINVAL) /* Should silently drop packet */ > error = 0; > > m_freem(m); > goto freecopy; > } >- } else { >- /* Loop detection */ >- for (mtag = m_tag_first(m); mtag != NULL; >- mtag = m_tag_next(m, mtag)) { >- if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE) >- continue; >- tdbi = (struct tdb_ident *)(mtag + 1); >- if (tdbi->spi == tdb->tdb_spi && >- tdbi->proto == tdb->tdb_sproto && >- tdbi->rdomain == tdb->tdb_rdomain && >- !bcmp(&tdbi->dst, &tdb->tdb_dst, >- sizeof(union sockaddr_union))) { >- sproto = 0; /* mark as no-IPsec-needed */ >- goto done_spd; >- } >- } >- >- /* We need to do IPsec */ >- bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst)); >- sspi = tdb->tdb_spi; >- sproto = tdb->tdb_sproto; > } >- >- /* Fall through to the routing/multicast handling code */ >- done_spd: > #endif /* IPSEC */ > > #if NPF > 0 >@@ -313,40 +262,12 @@ reroute: > * XXX ipsp_process_packet() calls ip6_output(), and there'll be no > * PMTU notification. is it okay? > */ >- if (sproto != 0) { >- tdb = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid), >- sspi, &sdst, sproto); >- if (tdb == NULL) { >- error = EHOSTUNREACH; >- m_freem(m); >- goto senderr; /*XXX*/ >- } >- >-#if NPF > 0 >- if ((encif = enc_getif(tdb->tdb_rdomain, >- tdb->tdb_tap)) == NULL || >- pf_test(AF_INET6, PF_FWD, encif, &m) != PF_PASS) { >- error = EHOSTUNREACH; >- m_freem(m); >- goto senderr; >- } >- if (m == NULL) >- goto senderr; >- /* >- * PF_TAG_REROUTE handling or not... >- * Packet is entering IPsec so the routing is >- * already overruled by the IPsec policy. >- * Until now the change was not reconsidered. >- * What's the behaviour? >- */ >- in6_proto_cksum_out(m, encif); >-#endif >- m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */ >- >+ if (tdb != NULL) { > /* Callee frees mbuf */ >- error = ipsp_process_packet(m, tdb, AF_INET6, 0); >- m_freem(mcopy); >- goto freert; >+ error = ip6_output_ipsec_send(tdb, m, 0, 1); >+ if (error) >+ goto senderr; >+ goto freecopy; > } > #endif /* IPSEC */ > >Index: netinet6/ip6_output.c >=================================================================== >RCS file: /cvs/src/sys/netinet6/ip6_output.c,v >retrieving revision 1.204 >diff -u -p -u -r1.204 ip6_output.c >--- netinet6/ip6_output.c 21 Jan 2016 11:23:48 -0000 1.204 >+++ netinet6/ip6_output.c 13 Apr 2016 21:47:09 -0000 >@@ -172,14 +172,7 @@ ip6_output(struct mbuf *m0, struct ip6_p > int hdrsplit = 0; > u_int8_t sproto = 0; > #ifdef IPSEC >- struct m_tag *mtag; >- union sockaddr_union sdst; >- struct tdb_ident *tdbi; >- u_int32_t sspi; >- struct tdb *tdb; >-#if NPF > 0 >- struct ifnet *encif; >-#endif >+ struct tdb *tdb = NULL; > #endif /* IPSEC */ > > #ifdef IPSEC >@@ -215,28 +208,9 @@ ip6_output(struct mbuf *m0, struct ip6_p > } > > #ifdef IPSEC >- if (!ipsec_in_use && !inp) >- goto done_spd; >- >- /* >- * Check if there was an outgoing SA bound to the flow >- * from a transport protocol. >- */ >- >- /* Do we have any pending SAs to apply ? */ >- tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr), >- &error, IPSP_DIRECTION_OUT, NULL, inp, 0); >- >- if (tdb == NULL) { >- if (error == 0) { >- /* >- * No IPsec processing required, we'll just send the >- * packet out. >- */ >- sproto = 0; >- >- /* Fall through to routing/multicast handling */ >- } else { >+ if (ipsec_in_use || inp) { >+ tdb = ip6_output_ipsec_lookup(m, &error, inp); >+ if (error != 0) { > /* > * -EINVAL is used to indicate that the packet should > * be silently dropped, typically because we've asked >@@ -247,31 +221,7 @@ ip6_output(struct mbuf *m0, struct ip6_p > > goto freehdrs; > } >- } else { >- /* Loop detection */ >- for (mtag = m_tag_first(m); mtag != NULL; >- mtag = m_tag_next(m, mtag)) { >- if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE) >- continue; >- tdbi = (struct tdb_ident *)(mtag + 1); >- if (tdbi->spi == tdb->tdb_spi && >- tdbi->proto == tdb->tdb_sproto && >- tdbi->rdomain == tdb->tdb_rdomain && >- !bcmp(&tdbi->dst, &tdb->tdb_dst, >- sizeof(union sockaddr_union))) { >- sproto = 0; /* mark as no-IPsec-needed */ >- goto done_spd; >- } >- } >- >- /* We need to do IPsec */ >- bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst)); >- sspi = tdb->tdb_spi; >- sproto = tdb->tdb_sproto; > } >- >- /* Fall through to the routing/multicast handling code */ >- done_spd: > #endif /* IPSEC */ > > /* >@@ -469,55 +419,19 @@ reroute: > } > > #ifdef IPSEC >- /* >- * Check if the packet needs encapsulation. >- * ipsp_process_packet will never come back to here. >- */ >- if (sproto != 0) { >+ if (tdb) { > /* > * XXX what should we do if ip6_hlim == 0 and the > * packet gets tunneled? > */ >- >- tdb = gettdb(rtable_l2(m->m_pkthdr.ph_rtableid), >- sspi, &sdst, sproto); >- if (tdb == NULL) { >- error = EHOSTUNREACH; >- m_freem(m); >- goto done; >- } >- >-#if NPF > 0 >- if ((encif = enc_getif(tdb->tdb_rdomain, >- tdb->tdb_tap)) == NULL || >- pf_test(AF_INET6, PF_OUT, encif, &m) != PF_PASS) { >- error = EHOSTUNREACH; >- m_freem(m); >- goto done; >- } >- if (m == NULL) >- goto done; >- /* >- * PF_TAG_REROUTE handling or not... >- * Packet is entering IPsec so the routing is >- * already overruled by the IPsec policy. >- * Until now the change was not reconsidered. >- * What's the behaviour? >- */ >- in6_proto_cksum_out(m, encif); >-#endif >- m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */ >- >- /* Callee frees mbuf */ > /* > * if we are source-routing, do not attempt to tunnel the > * packet just because ip6_dst is different from what tdb has. > * XXX > */ >- error = ipsp_process_packet(m, tdb, AF_INET6, >- exthdrs.ip6e_rthdr ? 1 : 0); >- >- return error; /* Nothing more to be done */ >+ error = ip6_output_ipsec_send(tdb, m, >+ exthdrs.ip6e_rthdr ? 1 : 0, 0); >+ goto done; > } > #endif /* IPSEC */ > >@@ -2944,3 +2858,70 @@ in6_proto_cksum_out(struct mbuf *m, stru > m->m_pkthdr.csum_flags &= ~M_ICMP_CSUM_OUT; /* Clear */ > } > } >+ >+#ifdef IPSEC >+struct tdb * >+ip6_output_ipsec_lookup(struct mbuf *m, int *error, struct inpcb *inp) >+{ >+ struct tdb *tdb; >+ struct m_tag *mtag; >+ struct tdb_ident *tdbi; >+ >+ /* >+ * Check if there was an outgoing SA bound to the flow >+ * from a transport protocol. >+ */ >+ >+ /* Do we have any pending SAs to apply ? */ >+ tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr), >+ error, IPSP_DIRECTION_OUT, NULL, inp, 0); >+ >+ if (tdb != NULL) { >+ /* Loop detection */ >+ for (mtag = m_tag_first(m); mtag != NULL; >+ mtag = m_tag_next(m, mtag)) { >+ if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE) >+ continue; >+ tdbi = (struct tdb_ident *)(mtag + 1); >+ if (tdbi->spi == tdb->tdb_spi && >+ tdbi->proto == tdb->tdb_sproto && >+ tdbi->rdomain == tdb->tdb_rdomain && >+ !bcmp(&tdbi->dst, &tdb->tdb_dst, >+ sizeof(union sockaddr_union))) >+ tdb = NULL; >+ } >+ /* We need to do IPsec */ >+ } >+ return tdb; >+} >+ >+int >+ip6_output_ipsec_send(struct tdb *tdb, struct mbuf *m, int tunalready, int >fwd) >+{ >+#if NPF > 0 >+ struct ifnet *encif; >+#endif >+ >+#if NPF > 0 >+ if ((encif = enc_getif(tdb->tdb_rdomain, tdb->tdb_tap)) == NULL || >+ pf_test(AF_INET6, fwd ? PF_FWD : PF_OUT, encif, &m) != PF_PASS) { >+ m_freem(m); >+ return EHOSTUNREACH; >+ } >+ if (m == NULL) >+ return 0; >+ /* >+ * PF_TAG_REROUTE handling or not... >+ * Packet is entering IPsec so the routing is >+ * already overruled by the IPsec policy. >+ * Until now the change was not reconsidered. >+ * What's the behaviour? >+ */ >+ in6_proto_cksum_out(m, encif); >+#endif >+ m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */ >+ >+ /* Callee frees mbuf */ >+ return ipsp_process_packet(m, tdb, AF_INET6, tunalready); >+} >+#endif /* IPSEC */ >Index: netinet6/ip6_var.h >=================================================================== >RCS file: /cvs/src/sys/netinet6/ip6_var.h,v >retrieving revision 1.57 >diff -u -p -u -r1.57 ip6_var.h >--- netinet6/ip6_var.h 3 Dec 2015 21:11:54 -0000 1.57 >+++ netinet6/ip6_var.h 13 Apr 2016 21:47:08 -0000 >@@ -304,6 +304,14 @@ struct rtentry *in6_selectroute(struct s > struct route_in6 *, unsigned int rtableid); > > u_int32_t ip6_randomflowlabel(void); >+ >+#ifdef IPSEC >+struct tdb; >+struct tdb * >+ ip6_output_ipsec_lookup(struct mbuf *, int *, struct inpcb *); >+int ip6_output_ipsec_send(struct tdb *, struct mbuf *, int, int); >+#endif /* IPSEC */ >+ > #endif /* _KERNEL */ > > #endif /* !_NETINET6_IP6_VAR_H_ */