This RFC adds IPsec ESP tunnels to the userspace datapath, so that
OVS-DPDK can encrypt traffic in its PMD threads.  Today, IPsec in OVS
relies on the kernel's xfrm, which the userspace datapath cannot use
without sending traffic through the kernel.

I would like feedback on the design and interfaces before polishing it.
The questions are below.


What it does
============

A new 'esp' tunnel port carries IPv4 and IPv6 packets in ESP tunnel mode
(RFC 4303) with AES-GCM (RFC 4106), over IPv4 or IPv6:

  $ ovs-vsctl add-port br0 esp0 -- set int esp0 type=esp \
      options:remote_ip=192.168.25.2 \
      options:esp_keying=ike options:esp_if_id=7

 - Keys come from an IKE daemon through new 'esp/*' unixctl commands, or
   are configured manually.
 - It supports Extended Sequence Numbers, anti-replay, UDP encapsulation
   for NAT traversal, and software TSO.
 - Rekeying swaps the outbound SA atomically, without changing datapath
   flows.
 - AES-GCM uses the Intel IPsec Multi-Buffer library if available at
   build time, and OpenSSL otherwise.

For IKE, I wrote a strongSwan plugin, 'kernel-ovs', which implements
strongSwan's kernel_ipsec_t over the unixctl socket:
https://github.com/trajs/strongswan/tree/kernel-ovs
It is not upstream in strongSwan.  It builds with --enable-kernel-ovs on
that branch, based on 5.9.13.  My tests ran it as a separately built
module in Ubuntu's strongSwan 5.9.13.

The OVS series is also at:
https://github.com/trajs/ovs/tree/ipsec-dpdk


Patches
=======

  1     netdev: push_header() may now fail, for all tunnel types.
  2     The ESP library: SAs, AES-GCM, anti-replay.
  3     The 'esp' tunnel port.
  4     Per-SA statistics and 'esp/show'.
  5     Software TSO for ESP.
  6     UDP encapsulation.
  7     unixctl commands with secret arguments.
  8     IKE keying through 'esp/*' commands.
  9     Documentation.
  10    IPsec Multi-Buffer library backend.
  11    Per-thread packet counts, so one SA scales across PMDs.
  12    Reporting of missing SAs.

Patch 1 changes shared code and could go in by itself.


Results
=======

One PMD thread, one SA, Intel Core Ultra 9 285HX (AVX2), E810 25G, with
pktgen as the traffic source.  The numbers are averages of two or three
runs, and were measured before patch 11, which changes the per-packet
counters.  Its effect is shown below.

ESP alone, by crypto backend (also in patch 10):

              64 bytes        512 bytes        1400 bytes
  encrypt
    OpenSSL   3.7 Mpps        9.4 Gbit/s       16.6 Gbit/s
    IPsec-MB  6.0 Mpps        13.6 Gbit/s      19.3 Gbit/s
  decrypt
    OpenSSL   4.0 Mpps        9.5 Gbit/s       18.7 Gbit/s
    IPsec-MB  6.5 Mpps        12.2 Gbit/s      18.9 Gbit/s

Geneve in ESP on one core, against kernel OVS with xfrm on the same
packets.  Kernel encapsulation is at full rate.  Kernel decapsulation
livelocks at full line rate, so its figures are the best lossless rate
from a sweep of the offered rate:

              OVS-DPDK                  kernel
  encap   64  5.02 Mpps                 0.88 Mpps        5.7x
         512  2.78 Mpps  11.4 Gbit/s    0.77 Mpps        3.6x
        1400  1.66 Mpps  18.6 Gbit/s    0.66 Mpps        2.5x
  decap   64  4.62 Mpps                 0.80 Mpps        5.8x
         512  2.47 Mpps  10.1 Gbit/s    0.70 Mpps        3.5x
        1400  1.60 Mpps  18.0 Gbit/s    0.60 Mpps        2.7x

Round-trip latency added by ESP on top of Geneve, median:

              OVS-DPDK    kernel
          64  +0.1 us     +1.9 us
         512  +0.7 us     +2.2 us
        1400  +0.9 us     +2.3 us (1350 bytes)

The OVS-DPDK latency used pktgen probes over vhost-user and the kernel
used sockperf over sockets, so only the added cost is comparable, not the
totals.  The OVS-DPDK 1400-byte figure is at 5% load, the others at 1%.

Encrypting 64-byte packets with two PMDs sharing one outbound SA, with
and without patch 11, in a later run with a different measurement, so
compare these only with each other:

          before     after
  1 PMD   6.4 Mpps   6.6 Mpps
  2 PMDs  9.5 Mpps   11.2 Mpps

That is about 1.7 times one PMD; the sequence number stays shared, and
pktgen tops out near 12.7 Mpps.  Decryption with several PMDs and many
SAs have not been measured.  Raw ESP has no port numbers, so I expect
one tunnel to land on one receive queue.


Testing
=======

On this series, based on daafbd0a2:

  make check             passed on the first and last patches,
                         10 skipped
  each patch             builds with --enable-Werror, and passes the
                         tunnel and ESP tests
  check-system-userspace 166 passed, 56 skipped
  check-system-tso       147 passed, 49 skipped
  check-kernel           173 passed, 52 skipped (ESP tests skip)
  check-dpdk             155 passed, 68 skipped
  check-valgrind         ESP tests only: no leaks or invalid accesses
  build variants         IPsec-MB and OpenSSL; OpenSSL only; no crypto
  other builds           each patch with sparse, clang and 32-bit
  make distcheck         passed
  sanitizers             clang address and undefined: make check and the
                         ESP system tests passed, with no reports
  clang analyzer         no new reports against main

The system-test counts are from just before the last build-only fixes.
GitHub Actions passes on the final patches: all jobs, including macOS,
32-bit, sanitizers and system tests, and FreeBSD:
https://github.com/trajs/ovs/actions/runs/41384870082

By hand on E810 ports, against Linux kernel IPsec with manual keys and
with a second strongSwan: traffic, rekeys under traffic, ESN, several
CHILD_SAs, and restarts of ovs-vswitchd and charon.

A few tests are intermittent on my machine.  'conntrack - limit by zone'
and 'tunnel - table version' also fail occasionally on clean main.
'flow resume with geneve tun_metadata' failed once in check-dpdk and did
not recur in later runs on this series or on main.  The system tests
were run in a separate network namespace.


Known limitations
=================

 - Decrypted packets are not checked against the traffic selectors that
   IKE negotiated, which RFC 4301 section 5.2 requires.  OpenFlow rules
   must enforce them.  See question 1.
 - Keys are wiped from the SA, the command's own copies and unixctl's
   copies, but not from the jsonrpc receive buffer, the per-thread
   OpenSSL contexts, or the IPsec-MB context on the stack.
 - AES-GCM only.  No fragmentation or reassembly of ESP packets.
 - No MOBIKE or NAT mapping changes (the plugin's update_sa is not
   implemented).
 - With UDP encapsulation, IKE cannot share the port on that address.
 - One ovs-vswitchd serves one kernel-ovs charon, which flushes the
   IKE-keyed SAs when it starts.
 - IPsec-MB is not added to the packaging or CI.


Questions
=========

 1. Traffic selectors: is "OpenFlow is the policy" acceptable if it is
    documented, or should the datapath enforce selectors, at the cost of
    a lookup per packet?
 2. Is the Intel IPsec Multi-Buffer library acceptable as an optional
    dependency?  It gains up to 61% over OpenSSL at small packets.
 3. How should this relate to ovs-monitor-ipsec?  Should it learn to
    drive these tunnels, or do they stay separate?
 4. Is unixctl the right interface for an IKE daemon?  The commands and
    secret arguments are new, and the keys cross a local socket.
 5. Should push_header() returning an error (patch 1) go in on its own?

Parts of this series were written with an AI assistant, as the
Assisted-by tags show.  I have reviewed it and take responsibility for it.

Thilak Raj Surendra Babu (12):
  netdev: Allow tunnel push_header() to fail.
  esp: Add IPsec ESP security associations with AES-GCM.
  userspace: Add IPsec ESP tunnel support.
  esp: Add per-SA statistics and the 'esp/show' command.
  netdev: Segment TSO packets in software for ESP tunnels.
  userspace: Add UDP encapsulation of ESP for NAT traversal.
  unixctl: Allow commands with secret arguments.
  esp: Let an IKE daemon install the security associations.
  Documentation: Describe esp tunnels keyed by IKE.
  esp: Use the Intel IPsec Multi-Buffer library for AES-GCM.
  esp: Count packets per thread, to scale across PMDs.
  esp: Report missing security associations.

 Documentation/faq/configuration.rst     |   59 ++
 Documentation/faq/releases.rst          |    1 +
 Documentation/intro/install/general.rst |    5 +
 NEWS                                    |   13 +
 configure.ac                            |    1 +
 include/linux/openvswitch.h             |    1 +
 lib/automake.mk                         |    5 +
 lib/dp-packet-gso.c                     |    7 +-
 lib/dpif-netlink-rtnl.c                 |    4 +
 lib/dpif-netlink.c                      |    5 +
 lib/esp-ctl.c                           |  607 ++++++++++++++
 lib/esp-ctl.h                           |   34 +
 lib/esp.c                               | 1013 +++++++++++++++++++++++
 lib/esp.h                               |  129 +++
 lib/netdev-native-tnl.c                 |  221 ++++-
 lib/netdev-native-tnl.h                 |   21 +-
 lib/netdev-provider.h                   |   13 +-
 lib/netdev-vport-private.h              |    7 +
 lib/netdev-vport.c                      |  515 +++++++++++-
 lib/netdev-vport.h                      |    7 +
 lib/netdev.c                            |   29 +-
 lib/netdev.h                            |   10 +
 lib/odp-util.c                          |   43 +
 lib/packets.h                           |    4 +-
 lib/tnl-ports.c                         |   11 +-
 lib/unixctl.c                           |   37 +-
 lib/unixctl.h                           |    3 +
 lib/util.c                              |   12 +
 lib/util.h                              |    1 +
 m4/openvswitch.m4                       |   33 +
 ofproto/ofproto-dpif-xlate.c            |   21 +-
 ofproto/ofproto-tnl-unixctl.man         |   31 +
 python/ovs/flow/odp.py                  |    7 +
 python/ovs/tests/test_odp.py            |   15 +
 tests/automake.mk                       |    1 +
 tests/library.at                        |    6 +
 tests/odp.at                            |    5 +
 tests/system-kmod-macros.at             |    8 +
 tests/system-traffic.at                 |  108 +++
 tests/system-userspace-macros.at        |    9 +
 tests/test-esp.c                        |  420 ++++++++++
 tests/tunnel-push-pop-ipv6.at           |   54 ++
 tests/tunnel-push-pop.at                |  506 +++++++++++
 tests/tunnel.at                         |   84 ++
 vswitchd/vswitch.xml                    |  186 ++++-
 45 files changed, 4266 insertions(+), 46 deletions(-)
 create mode 100644 lib/esp-ctl.c
 create mode 100644 lib/esp-ctl.h
 create mode 100644 lib/esp.c
 create mode 100644 lib/esp.h
 create mode 100644 tests/test-esp.c

-- 
2.43.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to