OK.... let's do an experiment. Two c5.9xlarge instances.
$ ./netperf -H 10.0.161.101 -t UDP_STREAM -- -m 8970
MIGRATED UDP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.0.161.101
() port 0 AF_INET
Socket Message Elapsed Messages
Size Size Time Okay Errors Throughput
bytes bytes secs # # 10^6bits/sec
212992 8970 10.00 1114099 0 7994.75
212992 10.00 1114099 7994.75
OK, it gets less impressive if I limit myself to 1400-byte packets:
$ ./netperf -H 10.0.161.101 -t UDP_STREAM -- -m 1400
MIGRATED UDP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 10.0.161.101
() port 0 AF_INET
Socket Message Elapsed Messages
Size Size Time Okay Errors Throughput
bytes bytes secs # # 10^6bits/sec
212992 1400 10.00 5077116 0 5686.36
212992 10.00 5074446 5683.37
So... kernel ESP between the two. Here's a script which sets it up:
cat > espsetup.sh <<EOF
#!/bin/sh
KEY=0x1234567890123456789012345678901234567890123456789012345678901234
SPI1=0x12345678
SPI2=0x87654321
SRC=10.0.161.101
DST=10.0.186.131
LOCAL=172.16.0.1
REMOTE=172.16.0.2
if ip addr list dev eth0 | grep -q $DST; then
xDST=$SRC
SRC=$DST
DST=$xDST
xLOCAL=$REMOTE
REMOTE=$LOCAL
LOCAL=$xLOCAL
xSPI1=$SPI2
SPI2=$SPI1
SPI1=$xSPI1
fi
echo $SPI1 $SPI2
ip xfrm state del src $SRC dst $DST proto esp spi $SPI1
ip xfrm state del src $DST dst $SRC proto esp spi $SPI2
ip xfrm state add src $SRC dst $DST proto esp spi $SPI1 reqid $SPI1 mode tunnel
auth sha1 $KEY enc aes $KEY encap espinudp 8443 8443 $SRC
ip xfrm state add src $DST dst $SRC proto esp spi $SPI2 reqid $SPI2 mode tunnel
auth sha1 $KEY enc aes $KEY encap espinudp 8443 8443 $SRC
ip xfrm policy add src $LOCAL dst $REMOTE dir out tmpl src $SRC dst $DST proto
esp reqid $SPI1 mode tunnel
ip xfrm policy add src $REMOTE dst $LOCAL dir in tmpl src $DST dst $SRC proto
esp reqid $SPI2 mode tunnel
ip addr add $LOCAL dev lo
ip route add $REMOTE dev eth0 src $LOCAL
EOF
And if you want the kernel to actually receive and process the UDP frames, you
have to run something that binds the socket...
(http://techblog.newsnow.co.uk/2011/11/simple-udp-esp-encapsulation-nat-t-for.html)
cat > esplisten.pl <<EOF
#!/usr/bin/perl -w
use strict;
use Socket qw( IPPROTO_IP IPPROTO_UDP AF_INET SOCK_DGRAM SOL_SOCKET
SO_REUSEADDR INADDR_ANY sockaddr_in );
my $UDP_ENCAP = 100;
# UDP encapsulation types
my $UDP_ENCAP_ESPINUDP_NON_IKE = 1; # /* draft-ietf-ipsec-nat-t-ike-00/01 */
my $UDP_ENCAP_ESPINUDP = 2; # /* draft-ietf-ipsec-udp-encaps-06 */
my $UDP_ENCAP_L2TPINUDP = 3; # /* rfc2661 */
my $Sock;
socket( $Sock, AF_INET, SOCK_DGRAM, IPPROTO_UDP ) || die "::socket: $!";
setsockopt( $Sock, SOL_SOCKET, SO_REUSEADDR, pack( "l", 1 ) );
# struct sadb_x_policy {
# uint16_t sadb_x_policy_len;
# uint16_t sadb_x_policy_exttype;
# uint16_t sadb_x_policy_type;
# uint8_t sadb_x_policy_dir;
# uint8_t sadb_x_policy_reserved;
# uint32_t sadb_x_policy_id;
# uint32_t sadb_x_policy_priority;
# } __attribute__((packed));
# /* sizeof(struct sadb_x_policy) == 16 */
my $SADB_X_EXT_POLICY = 18;
my $IP_IPSEC_POLICY = 16;
my $IPSEC_POLICY_BYPASS = 4;
my $IPSEC_DIR_INBOUND = 1;
my $IPSEC_DIR_OUTBOUND = 2;
# policy.sadb_x_policy_len = sizeof(policy) / sizeof(u_int64_t);
# policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
# policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS;
# policy.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND;
my $policy1 = pack("SSSCCLL", 2, $SADB_X_EXT_POLICY, $IPSEC_POLICY_BYPASS,
$IPSEC_DIR_OUTBOUND, 0, 0, 0);
my $policy2 = pack("SSSCCLL", 2, $SADB_X_EXT_POLICY, $IPSEC_POLICY_BYPASS,
$IPSEC_DIR_INBOUND, 0, 0, 0);
# See
http://strongswan.sourcearchive.com/documentation/4.1.4/socket_8c-source.html
if( defined setsockopt( $Sock, IPPROTO_IP, $IP_IPSEC_POLICY, $policy1 ) ) {
print "setsockopt:: policy OK\n"; }
else { print "setsockopt:: policy FAIL\n"; }
if( defined setsockopt( $Sock, IPPROTO_IP, $IP_IPSEC_POLICY, $policy2 ) ) {
print "setsockopt:: policy OK\n"; }
else { print "setsockopt:: policy FAIL\n"; }
if( defined setsockopt( $Sock, IPPROTO_UDP, $UDP_ENCAP, $UDP_ENCAP_ESPINUDP) ) {
print "setsockopt:: UDP_ENCAP OK\n"; }
else { print "setsockopt:: UDP_ENCAP FAIL\n"; }
bind( $Sock, sockaddr_in( 8443, INADDR_ANY ) ) || die "::bind: $!";
sleep;
1;
EOF
Ok, how does that perform?
$ sudo perf record -a ./netperf -H 172.16.0.1 -t UDP_STREAM -- -m 1400
MIGRATED UDP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to 172.16.0.1 ()
port 0 AF_INET
Socket Message Elapsed Messages
Size Size Time Okay Errors Throughput
bytes bytes secs # # 10^6bits/sec
212992 1400 10.00 1198093 0 1341.86
212992 10.00 1198044 1341.80
At this point netperf is taking 100% of CPU, doing this:
Samples: 49K of event 'cycles', Event count (approx.): 32648308583
Overhead Command Shared Object Symbol
31.59% netperf [kernel.vmlinux] [k] sha_transform
17.49% netperf [kernel.vmlinux] [k] _aesni_enc1
2.88% netperf [kernel.vmlinux] [k] _raw_spin_lock
2.22% netperf [ena] [k] ena_start_xmit
1.26% netperf [kernel.vmlinux] [k] aesni_cbc_enc
1.24% swapper [kernel.vmlinux] [k] intel_idle
1.23% netperf [ena] [k] ena_com_prepare_tx
1.13% netperf [kernel.vmlinux] [k] fib_table_lookup
1.02% netperf [kernel.vmlinux] [k] entry_SYSCALL_64
0.99% netperf [kernel.vmlinux] [k] csum_partial_copy_generic
Next step... tricking OpenConnect on one end into talking to the kernel ESP on
the other.
With openssl s_server and a handful of canned responses, let's see how far I
can get...
HTTP/1.1 200 OK
Content-Length: 207
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<response>
<ip-address>172.16.0.1</ip-address>
<netmask>255.255.255.0</netmask>
<mtu>1200</mtu>
<gw-address>172.16.0.2</gw-address>
</response>
HTTP/1.1 200 OK
Content-Length: 122
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<response>
<hip-report-needed>no</hip-report-needed>
</response>
START_TUNNEL
I think I just need to add the ESP config into that initial config
response, then hack openconnect to bind to local UDP port 8443...
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ openconnect-devel mailing list [email protected] http://lists.infradead.org/mailman/listinfo/openconnect-devel
