examples/ipsec-secgw: add IPsec sample application

Sample app implementing an IPsec Security Geteway.
The main goal of this app is to show the use of cryptodev framework
in a "real world" application.

Currently only supported static IPv4 ESP IPsec tunnels for the following
algorithms:
- Cipher: AES-CBC, NULL
- Authentication: HMAC-SHA1, NULL

Not supported:
- SA auto negotiation (No IKE implementation)
- chained mbufs

Signed-off-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
Acked-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
This commit is contained in:
Sergio Gonzalez Monroy 2016-03-11 02:12:40 +00:00 committed by Thomas Monjalon
parent ab8536d538
commit d299106e8e
15 changed files with 3711 additions and 0 deletions

View File

@ -566,6 +566,10 @@ M: Pablo de Lara <pablo.de.lara.guarch@intel.com>
F: examples/helloworld/
F: doc/guides/sample_app_ug/hello_world.rst
M: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
F: examples/ipsec-secgw/
F: doc/guides/sample_app_ug/ipsec_secgw.rst
F: examples/ipv4_multicast/
F: doc/guides/sample_app_ug/ipv4_multicast.rst

View File

@ -148,6 +148,9 @@ Examples
vhost-switch often fails to allocate mbuf when dequeue from vring because it
wrongly calculates the number of mbufs needed.
* **examples/ipsec-secgw: ipsec security gateway**
New application implementing an IPsec Security Gateway.
Other
~~~~~

View File

@ -73,6 +73,7 @@ Sample Applications User Guide
proc_info
ptpclient
performance_thread
ipsec_secgw
**Figures**

View File

@ -0,0 +1,524 @@
.. BSD LICENSE
Copyright(c) 2016 Intel Corporation. All rights reserved.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Intel Corporation nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
IPsec Security Gateway Sample Application
=========================================
The IPsec Security Gateway application is an example of a "real world"
application using DPDK cryptodev framework.
Overview
--------
The application demonstrates the implementation of a Security Gateway
(not IPsec compliant, see Constraints bellow) using DPDK based on RFC4301,
RFC4303, RFC3602 and RFC2404.
Internet Key Exchange (IKE) is not implemented, so only manual setting of
Security Policies and Security Associations is supported.
The Security Policies (SP) are implemented as ACL rules, the Security
Associations (SA) are stored in a table and the Routing is implemented
using LPM.
The application classify the ports between Protected and Unprotected.
Thus, traffic received in an Unprotected or Protected port is consider
Inbound or Outbound respectively.
Path for IPsec Inbound traffic:
* Read packets from the port
* Classify packets between IPv4 and ESP.
* Inbound SA lookup for ESP packets based on their SPI
* Verification/Decryption
* Removal of ESP and outer IP header
* Inbound SP check using ACL of decrypted packets and any other IPv4 packet
we read.
* Routing
* Write packet to port
Path for IPsec Outbound traffic:
* Read packets from the port
* Outbound SP check using ACL of all IPv4 traffic
* Outbound SA lookup for packets that need IPsec protection
* Add ESP and outter IP header
* Encryption/Digest
* Routing
* Write packet to port
Constraints
-----------
* IPv4 traffic
* ESP tunnel mode
* EAS-CBC, HMAC-SHA1 and NULL
* Each SA must be handle by a unique lcore (1 RX queue per port)
* No chained mbufs
Compiling the Application
-------------------------
To compile the application:
#. Go to the sample application directory:
.. code-block:: console
export RTE_SDK=/path/to/rte_sdk
cd ${RTE_SDK}/examples/ipsec-secgw
#. Set the target (a default target is used if not specified). For example:
.. code-block:: console
export RTE_TARGET=x86_64-native-linuxapp-gcc
See the *DPDK Getting Started Guide* for possible RTE_TARGET values.
#. Build the application:
.. code-block:: console
make
Running the Application
-----------------------
The application has a number of command line options:
.. code-block:: console
./build/ipsec-secgw [EAL options] -- -p PORTMASK -P -u PORTMASK --config
(port,queue,lcore)[,(port,queue,lcore] --single-sa SAIDX --ep0|--ep1
where,
* -p PORTMASK: Hexadecimal bitmask of ports to configure
* -P: optional, sets all ports to promiscuous mode so that packets are
accepted regardless of the packet's Ethernet MAC destination address.
Without this option, only packets with the Ethernet MAC destination address
set to the Ethernet address of the port are accepted (default is enabled).
* -u PORTMASK: hexadecimal bitmask of unprotected ports
* --config (port,queue,lcore)[,(port,queue,lcore)]: determines which queues
from which ports are mapped to which cores
* --single-sa SAIDX: use a single SA for outbound traffic, bypassing the SP
on both Inbound and Outbound. This option is meant for debugging/performance
purposes.
* --ep0: configure the app as Endpoint 0.
* --ep1: configure the app as Endpoint 1.
Either one of --ep0 or --ep1 *must* be specified.
The main purpose of these options is two easily configure two systems
back-to-back that would forward traffic through an IPsec tunnel.
The mapping of lcores to port/queues is similar to other l3fwd applications.
For example, given the following command line:
.. code-block:: console
./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048
--vdev "cryptodev_null_pmd" -- -p 0xf -P -u 0x3
--config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" --ep0
where each options means:
* The -l option enables cores 20 and 21
* The -n option sets memory 4 channels
* The --socket-mem to use 2GB on socket 1
* The --vdev "cryptodev_null_pmd" option creates virtual NULL cryptodev PMD
* The -p option enables ports (detected) 0, 1, 2 and 3
* The -P option enables promiscuous mode
* The -u option sets ports 1 and 2 as unprotected, leaving 2 and 3 as protected
* The --config option enables one queue per port with the following mapping:
+----------+-----------+-----------+---------------------------------------+
| **Port** | **Queue** | **lcore** | **Description** |
| | | | |
+----------+-----------+-----------+---------------------------------------+
| 0 | 0 | 20 | Map queue 0 from port 0 to lcore 20. |
| | | | |
+----------+-----------+-----------+---------------------------------------+
| 1 | 0 | 20 | Map queue 0 from port 1 to lcore 20. |
| | | | |
+----------+-----------+-----------+---------------------------------------+
| 2 | 0 | 21 | Map queue 0 from port 2 to lcore 21. |
| | | | |
+----------+-----------+-----------+---------------------------------------+
| 3 | 0 | 21 | Map queue 0 from port 3 to lcore 21. |
| | | | |
+----------+-----------+-----------+---------------------------------------+
* The --ep0 options configures the app with a given set of SP, SA and Routing
entries as explained below in more detail.
Refer to the *DPDK Getting Started Guide* for general information on running
applications and the Environment Abstraction Layer (EAL) options.
The application would do a best effort to "map" crypto devices to cores, with
hardware devices having priority.
This means that if the application is using a single core and both hardware
and software crypto devices are detected, hardware devices will be used.
A way to achive the case where you want to force the use of virtual crypto
devices is to whitelist the ethernet devices needed and therefore implicitely
blacklisting all hardware crypto devices.
For example, something like the following command line:
.. code-block:: console
./build/ipsec-secgw -l 20,21 -n 4 --socket-mem 0,2048
-w 81:00.0 -w 81:00.1 -w 81:00.2 -w 81:00.3
--vdev "cryptodev_aesni_mb_pmd" --vdev "cryptodev_null_pmd" --
-p 0xf -P -u 0x3 --config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)"
--ep0
Configurations
--------------
The following sections provide some details on the default values used to
initialize the SP, SA and Routing tables.
Currently all the configuration is hard coded into the application.
Security Policy Initialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As mention in the overview, the Security Policies are ACL rules.
The application defines two ACLs, one each of Inbound and Outbound, and
it replicates them per socket in use.
Following are the default rules:
Endpoint 0 Outbound Security Policies:
+---------+------------------+-----------+------------+
| **Src** | **Dst** | **proto** | **SA idx** |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.105.0/24 | Any | 5 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.106.0/24 | Any | 6 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.107.0/24 | Any | 7 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.108.0/24 | Any | 8 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.200.0/24 | Any | 9 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.250.0/24 | Any | BYPASS |
| | | | |
+---------+------------------+-----------+------------+
Endpoint 0 Inbound Security Policies:
+---------+------------------+-----------+------------+
| **Src** | **Dst** | **proto** | **SA idx** |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.115.0/24 | Any | 5 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.116.0/24 | Any | 6 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.117.0/24 | Any | 7 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.118.0/24 | Any | 8 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.210.0/24 | Any | 9 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.240.0/24 | Any | BYPASS |
| | | | |
+---------+------------------+-----------+------------+
Endpoint 1 Outbound Security Policies:
+---------+------------------+-----------+------------+
| **Src** | **Dst** | **proto** | **SA idx** |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.115.0/24 | Any | 5 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.116.0/24 | Any | 6 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.117.0/24 | Any | 7 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.118.0/24 | Any | 8 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.210.0/24 | Any | 9 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.240.0/24 | Any | BYPASS |
| | | | |
+---------+------------------+-----------+------------+
Endpoint 1 Inbound Security Policies:
+---------+------------------+-----------+------------+
| **Src** | **Dst** | **proto** | **SA idx** |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.105.0/24 | Any | 5 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.106.0/24 | Any | 6 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.107.0/24 | Any | 7 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.108.0/24 | Any | 8 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.200.0/24 | Any | 9 |
| | | | |
+---------+------------------+-----------+------------+
| Any | 192.168.250.0/24 | Any | BYPASS |
| | | | |
+---------+------------------+-----------+------------+
Security Association Initialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The SAs are kept in a array table.
For Inbound, the SPI is used as index module the table size.
This means that on a table for 100 SA, SPI 5 and 105 would use the same index
and that is not currently supported.
Notice that it is not an issue for Outbound traffic as we store the index and
not the SPI in the Security Policy.
All SAs configured with AES-CBC and HMAC-SHA1 share the same values for cipher
block size and key, and authentication digest size and key.
Following are the default values:
Endpoint 0 Outbound Security Associations:
+---------+------------+-----------+----------------+------------------+
| **SPI** | **Cipher** | **Auth** | **Tunnel src** | **Tunnel dst** |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 5 | AES-CBC | HMAC-SHA1 | 172.16.1.5 | 172.16.2.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 6 | AES-CBC | HMAC-SHA1 | 172.16.1.6 | 172.16.2.6 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 7 | AES-CBC | HMAC-SHA1 | 172.16.1.7 | 172.16.2.7 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 8 | AES-CBC | HMAC-SHA1 | 172.16.1.8 | 172.16.2.8 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 9 | NULL | NULL | 172.16.1.5 | 172.16.2.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
Endpoint 0 Inbound Security Associations:
+---------+------------+-----------+----------------+------------------+
| **SPI** | **Cipher** | **Auth** | **Tunnel src** | **Tunnel dst** |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 5 | AES-CBC | HMAC-SHA1 | 172.16.2.5 | 172.16.1.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 6 | AES-CBC | HMAC-SHA1 | 172.16.2.6 | 172.16.1.6 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 7 | AES-CBC | HMAC-SHA1 | 172.16.2.7 | 172.16.1.7 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 8 | AES-CBC | HMAC-SHA1 | 172.16.2.8 | 172.16.1.8 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 9 | NULL | NULL | 172.16.2.5 | 172.16.1.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
Endpoint 1 Outbound Security Associations:
+---------+------------+-----------+----------------+------------------+
| **SPI** | **Cipher** | **Auth** | **Tunnel src** | **Tunnel dst** |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 5 | AES-CBC | HMAC-SHA1 | 172.16.2.5 | 172.16.1.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 6 | AES-CBC | HMAC-SHA1 | 172.16.2.6 | 172.16.1.6 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 7 | AES-CBC | HMAC-SHA1 | 172.16.2.7 | 172.16.1.7 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 8 | AES-CBC | HMAC-SHA1 | 172.16.2.8 | 172.16.1.8 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 9 | NULL | NULL | 172.16.2.5 | 172.16.1.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
Endpoint 1 Inbound Security Associations:
+---------+------------+-----------+----------------+------------------+
| **SPI** | **Cipher** | **Auth** | **Tunnel src** | **Tunnel dst** |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 5 | AES-CBC | HMAC-SHA1 | 172.16.1.5 | 172.16.2.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 6 | AES-CBC | HMAC-SHA1 | 172.16.1.6 | 172.16.2.6 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 7 | AES-CBC | HMAC-SHA1 | 172.16.1.7 | 172.16.2.7 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 8 | AES-CBC | HMAC-SHA1 | 172.16.1.8 | 172.16.2.8 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
| 9 | NULL | NULL | 172.16.1.5 | 172.16.2.5 |
| | | | | |
+---------+------------+-----------+----------------+------------------+
Routing Initialization
~~~~~~~~~~~~~~~~~~~~~~
The Routing is implemented using LPM table.
Following default values:
Endpoint 0 Routing Table:
+------------------+----------+
| **Dst addr** | **Port** |
| | |
+------------------+----------+
| 172.16.2.5/32 | 0 |
| | |
+------------------+----------+
| 172.16.2.6/32 | 0 |
| | |
+------------------+----------+
| 172.16.2.7/32 | 1 |
| | |
+------------------+----------+
| 172.16.2.8/32 | 1 |
| | |
+------------------+----------+
| 192.168.115.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.116.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.117.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.118.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.210.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.240.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.250.0/24 | 0 |
| | |
+------------------+----------+
Endpoint 1 Routing Table:
+------------------+----------+
| **Dst addr** | **Port** |
| | |
+------------------+----------+
| 172.16.1.5/32 | 2 |
| | |
+------------------+----------+
| 172.16.1.6/32 | 2 |
| | |
+------------------+----------+
| 172.16.1.7/32 | 3 |
| | |
+------------------+----------+
| 172.16.1.8/32 | 3 |
| | |
+------------------+----------+
| 192.168.105.0/24 | 0 |
| | |
+------------------+----------+
| 192.168.106.0/24 | 0 |
| | |
+------------------+----------+
| 192.168.107.0/24 | 1 |
| | |
+------------------+----------+
| 192.168.108.0/24 | 1 |
| | |
+------------------+----------+
| 192.168.200.0/24 | 0 |
| | |
+------------------+----------+
| 192.168.240.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.250.0/24 | 0 |
| | |
+------------------+----------+

View File

@ -82,5 +82,6 @@ DIRS-y += vmdq
DIRS-y += vmdq_dcb
DIRS-$(CONFIG_RTE_LIBRTE_POWER) += vm_power_manager
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += l2fwd-crypto
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += ipsec-secgw
include $(RTE_SDK)/mk/rte.extsubdir.mk

View File

@ -0,0 +1,58 @@
# BSD LICENSE
#
# Copyright(c) 2016 Intel Corporation. All rights reserved.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif
# Default target, can be overridden by command line or environment
RTE_TARGET ?= x86_64-native-linuxapp-gcc
include $(RTE_SDK)/mk/rte.vars.mk
APP = ipsec-secgw
CFLAGS += -O3 -gdwarf-2
CFLAGS += $(WERROR_FLAGS)
VPATH += $(SRCDIR)/librte_ipsec
#
# all source are stored in SRCS-y
#
SRCS-y += ipsec.c
SRCS-y += esp.c
SRCS-y += sp.c
SRCS-y += sa.c
SRCS-y += rt.c
SRCS-y += ipsec-secgw.c
include $(RTE_SDK)/mk/rte.extapp.mk

250
examples/ipsec-secgw/esp.c Normal file
View File

@ -0,0 +1,250 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdint.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <rte_common.h>
#include <rte_memcpy.h>
#include <rte_crypto.h>
#include <rte_cryptodev.h>
#include <rte_random.h>
#include "ipsec.h"
#include "esp.h"
#include "ipip.h"
#define IP_ESP_HDR_SZ (sizeof(struct ip) + sizeof(struct esp_hdr))
static inline void
random_iv_u64(uint64_t *buf, uint16_t n)
{
unsigned left = n & 0x7;
unsigned i;
IPSEC_ASSERT((n & 0x3) == 0);
for (i = 0; i < (n >> 3); i++)
buf[i] = rte_rand();
if (left)
*((uint32_t *)&buf[i]) = (uint32_t)lrand48();
}
/* IPv4 Tunnel */
int
esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop)
{
int32_t payload_len;
struct rte_crypto_sym_op *sym_cop;
IPSEC_ASSERT(m != NULL);
IPSEC_ASSERT(sa != NULL);
IPSEC_ASSERT(cop != NULL);
payload_len = rte_pktmbuf_pkt_len(m) - IP_ESP_HDR_SZ - sa->iv_len -
sa->digest_len;
if ((payload_len & (sa->block_size - 1)) || (payload_len <= 0)) {
IPSEC_LOG(DEBUG, IPSEC_ESP, "payload %d not multiple of %u\n",
payload_len, sa->block_size);
return -EINVAL;
}
sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
sym_cop->m_src = m;
sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
sym_cop->cipher.data.length = payload_len;
sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, void*,
IP_ESP_HDR_SZ);
sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
IP_ESP_HDR_SZ);
sym_cop->cipher.iv.length = sa->iv_len;
sym_cop->auth.data.offset = sizeof(struct ip);
if (sa->auth_algo == RTE_CRYPTO_AUTH_AES_GCM)
sym_cop->auth.data.length = sizeof(struct esp_hdr);
else
sym_cop->auth.data.length = sizeof(struct esp_hdr) +
sa->iv_len + payload_len;
sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, void*,
rte_pktmbuf_pkt_len(m) - sa->digest_len);
sym_cop->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
rte_pktmbuf_pkt_len(m) - sa->digest_len);
sym_cop->auth.digest.length = sa->digest_len;
return 0;
}
int
esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop)
{
uint8_t *nexthdr, *pad_len;
uint8_t *padding;
uint16_t i;
IPSEC_ASSERT(m != NULL);
IPSEC_ASSERT(sa != NULL);
IPSEC_ASSERT(cop != NULL);
if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
IPSEC_LOG(ERR, IPSEC_ESP, "Failed crypto op\n");
return -1;
}
nexthdr = rte_pktmbuf_mtod_offset(m, uint8_t*,
rte_pktmbuf_pkt_len(m) - sa->digest_len - 1);
pad_len = nexthdr - 1;
padding = pad_len - *pad_len;
for (i = 0; i < *pad_len; i++) {
if (padding[i] != i) {
IPSEC_LOG(ERR, IPSEC_ESP, "invalid pad_len field\n");
return -EINVAL;
}
}
if (rte_pktmbuf_trim(m, *pad_len + 2 + sa->digest_len)) {
IPSEC_LOG(ERR, IPSEC_ESP,
"failed to remove pad_len + digest\n");
return -EINVAL;
}
return ip4ip_inbound(m, sizeof(struct esp_hdr) + sa->iv_len);
}
int
esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop)
{
uint16_t pad_payload_len, pad_len;
struct ip *ip;
struct esp_hdr *esp;
int i;
char *padding;
struct rte_crypto_sym_op *sym_cop;
IPSEC_ASSERT(m != NULL);
IPSEC_ASSERT(sa != NULL);
IPSEC_ASSERT(cop != NULL);
/* Payload length */
pad_payload_len = RTE_ALIGN_CEIL(rte_pktmbuf_pkt_len(m) + 2,
sa->block_size);
pad_len = pad_payload_len - rte_pktmbuf_pkt_len(m);
rte_prefetch0(rte_pktmbuf_mtod_offset(m, void *,
rte_pktmbuf_pkt_len(m)));
/* Check maximum packet size */
if (unlikely(IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len +
sa->digest_len > IP_MAXPACKET)) {
IPSEC_LOG(DEBUG, IPSEC_ESP, "ipsec packet is too big\n");
return -EINVAL;
}
padding = rte_pktmbuf_append(m, pad_len + sa->digest_len);
IPSEC_ASSERT(padding != NULL);
ip = ip4ip_outbound(m, sizeof(struct esp_hdr) + sa->iv_len,
sa->src, sa->dst);
esp = (struct esp_hdr *)(ip + 1);
esp->spi = sa->spi;
esp->seq = htonl(sa->seq++);
IPSEC_LOG(DEBUG, IPSEC_ESP, "pktlen %u\n", rte_pktmbuf_pkt_len(m));
/* Fill pad_len using default sequential scheme */
for (i = 0; i < pad_len - 2; i++)
padding[i] = i + 1;
padding[pad_len - 2] = pad_len - 2;
padding[pad_len - 1] = IPPROTO_IPIP;
sym_cop = (struct rte_crypto_sym_op *)(cop + 1);
sym_cop->m_src = m;
sym_cop->cipher.data.offset = IP_ESP_HDR_SZ + sa->iv_len;
sym_cop->cipher.data.length = pad_payload_len;
sym_cop->cipher.iv.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
IP_ESP_HDR_SZ);
sym_cop->cipher.iv.phys_addr = rte_pktmbuf_mtophys_offset(m,
IP_ESP_HDR_SZ);
sym_cop->cipher.iv.length = sa->iv_len;
sym_cop->auth.data.offset = sizeof(struct ip);
sym_cop->auth.data.length = sizeof(struct esp_hdr) + sa->iv_len +
pad_payload_len;
sym_cop->auth.digest.data = rte_pktmbuf_mtod_offset(m, uint8_t *,
IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
sym_cop->auth.digest.phys_addr = rte_pktmbuf_mtophys_offset(m,
IP_ESP_HDR_SZ + sa->iv_len + pad_payload_len);
sym_cop->auth.digest.length = sa->digest_len;
if (sa->cipher_algo == RTE_CRYPTO_CIPHER_AES_CBC)
random_iv_u64((uint64_t *)sym_cop->cipher.iv.data,
sym_cop->cipher.iv.length);
return 0;
}
int
esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m __rte_unused,
struct ipsec_sa *sa __rte_unused,
struct rte_crypto_op *cop)
{
IPSEC_ASSERT(m != NULL);
IPSEC_ASSERT(sa != NULL);
IPSEC_ASSERT(cop != NULL);
if (cop->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
IPSEC_LOG(ERR, IPSEC_ESP, "Failed crypto op\n");
return -1;
}
return 0;
}

View File

@ -0,0 +1,66 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __RTE_IPSEC_XFORM_ESP_H__
#define __RTE_IPSEC_XFORM_ESP_H__
struct mbuf;
/* RFC4303 */
struct esp_hdr {
uint32_t spi;
uint32_t seq;
/* Payload */
/* Padding */
/* Pad Length */
/* Next Header */
/* Integrity Check Value - ICV */
};
/* IPv4 Tunnel */
int
esp4_tunnel_inbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop);
int
esp4_tunnel_inbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop);
int
esp4_tunnel_outbound_pre_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop);
int
esp4_tunnel_outbound_post_crypto(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop);
#endif /* __RTE_IPSEC_XFORM_ESP_H__ */

103
examples/ipsec-secgw/ipip.h Normal file
View File

@ -0,0 +1,103 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __IPIP_H__
#define __IPIP_H__
#include <stdint.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <rte_mbuf.h>
#define IPV6_VERSION (6)
static inline struct ip *
ip4ip_outbound(struct rte_mbuf *m, uint32_t offset, uint32_t src, uint32_t dst)
{
struct ip *inip, *outip;
inip = rte_pktmbuf_mtod(m, struct ip*);
IPSEC_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
offset += sizeof(struct ip);
outip = (struct ip *)rte_pktmbuf_prepend(m, offset);
IPSEC_ASSERT(outip != NULL);
/* Per RFC4301 5.1.2.1 */
outip->ip_v = IPVERSION;
outip->ip_hl = 5;
outip->ip_tos = inip->ip_tos;
outip->ip_len = htons(rte_pktmbuf_data_len(m));
outip->ip_id = 0;
outip->ip_off = 0;
outip->ip_ttl = IPDEFTTL;
outip->ip_p = IPPROTO_ESP;
outip->ip_src.s_addr = src;
outip->ip_dst.s_addr = dst;
return outip;
}
static inline int
ip4ip_inbound(struct rte_mbuf *m, uint32_t offset)
{
struct ip *inip;
struct ip *outip;
outip = rte_pktmbuf_mtod(m, struct ip*);
IPSEC_ASSERT(outip->ip_v == IPVERSION);
offset += sizeof(struct ip);
inip = (struct ip *)rte_pktmbuf_adj(m, offset);
IPSEC_ASSERT(inip->ip_v == IPVERSION || inip->ip_v == IPV6_VERSION);
/* Check packet is still bigger than IP header (inner) */
IPSEC_ASSERT(rte_pktmbuf_pkt_len(m) > sizeof(struct ip));
/* RFC4301 5.1.2.1 Note 6 */
if ((inip->ip_tos & htons(IPTOS_ECN_ECT0 | IPTOS_ECN_ECT1)) &&
((outip->ip_tos & htons(IPTOS_ECN_CE)) == IPTOS_ECN_CE))
inip->ip_tos |= htons(IPTOS_ECN_CE);
return 0;
}
#endif /* __IPIP_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,203 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <netinet/in.h>
#include <netinet/ip.h>
#include <rte_branch_prediction.h>
#include <rte_log.h>
#include <rte_crypto.h>
#include <rte_cryptodev.h>
#include <rte_mbuf.h>
#include <rte_hash.h>
#include "ipsec.h"
static inline int
create_session(struct ipsec_ctx *ipsec_ctx __rte_unused, struct ipsec_sa *sa)
{
uint32_t cdev_id_qp = 0;
int32_t ret;
struct cdev_key key = { 0 };
key.lcore_id = (uint8_t)rte_lcore_id();
key.cipher_algo = (uint8_t)sa->cipher_algo;
key.auth_algo = (uint8_t)sa->auth_algo;
ret = rte_hash_lookup_data(ipsec_ctx->cdev_map, &key,
(void **)&cdev_id_qp);
if (ret < 0) {
IPSEC_LOG(ERR, IPSEC, "No cryptodev: core %u, cipher_algo %u, "
"auth_algo %u\n", key.lcore_id, key.cipher_algo,
key.auth_algo);
return -1;
}
IPSEC_LOG(DEBUG, IPSEC, "Create session for SA spi %u on cryptodev "
"%u qp %u\n", sa->spi, ipsec_ctx->tbl[cdev_id_qp].id,
ipsec_ctx->tbl[cdev_id_qp].qp);
sa->crypto_session = rte_cryptodev_sym_session_create(
ipsec_ctx->tbl[cdev_id_qp].id, sa->xforms);
sa->cdev_id_qp = cdev_id_qp;
return 0;
}
static inline void
enqueue_cop(struct cdev_qp *cqp, struct rte_crypto_op *cop)
{
int ret, i;
cqp->buf[cqp->len++] = cop;
if (cqp->len == MAX_PKT_BURST) {
ret = rte_cryptodev_enqueue_burst(cqp->id, cqp->qp,
cqp->buf, cqp->len);
if (ret < cqp->len) {
IPSEC_LOG(DEBUG, IPSEC, "Cryptodev %u queue %u:"
" enqueued %u crypto ops out of %u\n",
cqp->id, cqp->qp,
ret, cqp->len);
for (i = ret; i < cqp->len; i++)
rte_pktmbuf_free(cqp->buf[i]->sym->m_src);
}
cqp->in_flight += ret;
cqp->len = 0;
}
}
static inline uint16_t
ipsec_processing(struct ipsec_ctx *ipsec_ctx, struct rte_mbuf *pkts[],
struct ipsec_sa *sas[], uint16_t nb_pkts, uint16_t max_pkts)
{
int ret = 0, i, j, nb_cops;
struct ipsec_mbuf_metadata *priv;
struct rte_crypto_op *cops[max_pkts];
struct ipsec_sa *sa;
struct rte_mbuf *pkt;
for (i = 0; i < nb_pkts; i++) {
rte_prefetch0(sas[i]);
rte_prefetch0(pkts[i]);
priv = get_priv(pkts[i]);
sa = sas[i];
priv->sa = sa;
IPSEC_ASSERT(sa != NULL);
priv->cop.type = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
rte_prefetch0(&priv->sym_cop);
priv->cop.sym = &priv->sym_cop;
if ((unlikely(sa->crypto_session == NULL)) &&
create_session(ipsec_ctx, sa)) {
rte_pktmbuf_free(pkts[i]);
continue;
}
rte_crypto_op_attach_sym_session(&priv->cop,
sa->crypto_session);
ret = sa->pre_crypto(pkts[i], sa, &priv->cop);
if (unlikely(ret)) {
rte_pktmbuf_free(pkts[i]);
continue;
}
IPSEC_ASSERT(sa->cdev_id_qp < ipsec_ctx->nb_qps);
enqueue_cop(&ipsec_ctx->tbl[sa->cdev_id_qp], &priv->cop);
}
nb_pkts = 0;
for (i = 0; i < ipsec_ctx->nb_qps && nb_pkts < max_pkts; i++) {
struct cdev_qp *cqp;
cqp = &ipsec_ctx->tbl[ipsec_ctx->last_qp++];
if (ipsec_ctx->last_qp == ipsec_ctx->nb_qps)
ipsec_ctx->last_qp %= ipsec_ctx->nb_qps;
if (cqp->in_flight == 0)
continue;
nb_cops = rte_cryptodev_dequeue_burst(cqp->id, cqp->qp,
cops, max_pkts - nb_pkts);
cqp->in_flight -= nb_cops;
for (j = 0; j < nb_cops; j++) {
pkt = cops[j]->sym->m_src;
rte_prefetch0(pkt);
priv = get_priv(pkt);
sa = priv->sa;
IPSEC_ASSERT(sa != NULL);
ret = sa->post_crypto(pkt, sa, cops[j]);
if (unlikely(ret))
rte_pktmbuf_free(pkt);
else
pkts[nb_pkts++] = pkt;
}
}
/* return packets */
return nb_pkts;
}
uint16_t
ipsec_inbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
uint16_t nb_pkts, uint16_t len)
{
struct ipsec_sa *sas[nb_pkts];
inbound_sa_lookup(ctx->sa_ctx, pkts, sas, nb_pkts);
return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
}
uint16_t
ipsec_outbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
uint32_t sa_idx[], uint16_t nb_pkts, uint16_t len)
{
struct ipsec_sa *sas[nb_pkts];
outbound_sa_lookup(ctx->sa_ctx, sa_idx, sas, nb_pkts);
return ipsec_processing(ctx, pkts, sas, nb_pkts, len);
}

View File

@ -0,0 +1,192 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __IPSEC_H__
#define __IPSEC_H__
#include <stdint.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <rte_byteorder.h>
#include <rte_ip.h>
#include <rte_crypto.h>
#define RTE_LOGTYPE_IPSEC RTE_LOGTYPE_USER1
#define RTE_LOGTYPE_IPSEC_ESP RTE_LOGTYPE_USER2
#define RTE_LOGTYPE_IPSEC_IPIP RTE_LOGTYPE_USER3
#define MAX_PKT_BURST 32
#define MAX_QP_PER_LCORE 256
#ifdef IPSEC_DEBUG
#define IPSEC_ASSERT(exp) \
if (!(exp)) { \
rte_panic("line%d\tassert \"" #exp "\" failed\n", __LINE__); \
}
#define IPSEC_LOG RTE_LOG
#else
#define IPSEC_ASSERT(exp) do {} while (0)
#define IPSEC_LOG(...) do {} while (0)
#endif /* IPSEC_DEBUG */
#define MAX_DIGEST_SIZE 32 /* Bytes -- 256 bits */
#define uint32_t_to_char(ip, a, b, c, d) do {\
*a = (unsigned char)(ip >> 24 & 0xff);\
*b = (unsigned char)(ip >> 16 & 0xff);\
*c = (unsigned char)(ip >> 8 & 0xff);\
*d = (unsigned char)(ip & 0xff);\
} while (0)
#define DEFAULT_MAX_CATEGORIES 1
#define IPSEC_SA_MAX_ENTRIES (64) /* must be power of 2, max 2 power 30 */
#define SPI2IDX(spi) (spi & (IPSEC_SA_MAX_ENTRIES - 1))
#define INVALID_SPI (0)
#define DISCARD (0x80000000)
#define BYPASS (0x40000000)
#define PROTECT_MASK (0x3fffffff)
#define PROTECT(sa_idx) (SPI2IDX(sa_idx) & PROTECT_MASK) /* SA idx 30 bits */
#define IPSEC_XFORM_MAX 2
struct rte_crypto_xform;
struct ipsec_xform;
struct rte_cryptodev_session;
struct rte_mbuf;
struct ipsec_sa;
typedef int (*ipsec_xform_fn)(struct rte_mbuf *m, struct ipsec_sa *sa,
struct rte_crypto_op *cop);
struct ipsec_sa {
uint32_t spi;
uint32_t cdev_id_qp;
uint32_t src;
uint32_t dst;
struct rte_cryptodev_sym_session *crypto_session;
struct rte_crypto_sym_xform *xforms;
ipsec_xform_fn pre_crypto;
ipsec_xform_fn post_crypto;
enum rte_crypto_cipher_algorithm cipher_algo;
enum rte_crypto_auth_algorithm auth_algo;
uint16_t digest_len;
uint16_t iv_len;
uint16_t block_size;
uint16_t flags;
uint32_t seq;
} __rte_cache_aligned;
struct ipsec_mbuf_metadata {
struct ipsec_sa *sa;
struct rte_crypto_op cop;
struct rte_crypto_sym_op sym_cop;
};
struct cdev_qp {
uint16_t id;
uint16_t qp;
uint16_t in_flight;
uint16_t len;
struct rte_crypto_op *buf[MAX_PKT_BURST] __rte_aligned(sizeof(void *));
};
struct ipsec_ctx {
struct rte_hash *cdev_map;
struct sp_ctx *sp_ctx;
struct sa_ctx *sa_ctx;
uint16_t nb_qps;
uint16_t last_qp;
struct cdev_qp tbl[MAX_QP_PER_LCORE];
};
struct cdev_key {
uint16_t lcore_id;
uint8_t cipher_algo;
uint8_t auth_algo;
};
struct socket_ctx {
struct sa_ctx *sa_ipv4_in;
struct sa_ctx *sa_ipv4_out;
struct sp_ctx *sp_ipv4_in;
struct sp_ctx *sp_ipv4_out;
struct rt_ctx *rt_ipv4;
struct rte_mempool *mbuf_pool;
};
uint16_t
ipsec_inbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
uint16_t nb_pkts, uint16_t len);
uint16_t
ipsec_outbound(struct ipsec_ctx *ctx, struct rte_mbuf *pkts[],
uint32_t sa_idx[], uint16_t nb_pkts, uint16_t len);
static inline uint16_t
ipsec_metadata_size(void)
{
return sizeof(struct ipsec_mbuf_metadata);
}
static inline struct ipsec_mbuf_metadata *
get_priv(struct rte_mbuf *m)
{
return RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
}
int
inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx);
void
inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
struct ipsec_sa *sa[], uint16_t nb_pkts);
void
outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
struct ipsec_sa *sa[], uint16_t nb_pkts);
void
sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
void
sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
void
rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep);
#endif /* __IPSEC_H__ */

144
examples/ipsec-secgw/rt.c Normal file
View File

@ -0,0 +1,144 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Routing Table (RT)
*/
#include <rte_lpm.h>
#include <rte_errno.h>
#include "ipsec.h"
#define RT_IPV4_MAX_RULES 64
struct ipv4_route {
uint32_t ip;
uint8_t depth;
uint8_t if_out;
};
/* In the default routing table we have:
* ep0 protected ports 0 and 1, and unprotected ports 2 and 3.
*/
static struct ipv4_route rt_ipv4_ep0[] = {
{ IPv4(172, 16, 2, 5), 32, 0 },
{ IPv4(172, 16, 2, 6), 32, 0 },
{ IPv4(172, 16, 2, 7), 32, 1 },
{ IPv4(172, 16, 2, 8), 32, 1 },
{ IPv4(192, 168, 115, 0), 24, 2 },
{ IPv4(192, 168, 116, 0), 24, 2 },
{ IPv4(192, 168, 117, 0), 24, 3 },
{ IPv4(192, 168, 118, 0), 24, 3 },
{ IPv4(192, 168, 210, 0), 24, 2 },
{ IPv4(192, 168, 240, 0), 24, 2 },
{ IPv4(192, 168, 250, 0), 24, 0 }
};
/* In the default routing table we have:
* ep1 protected ports 0 and 1, and unprotected ports 2 and 3.
*/
static struct ipv4_route rt_ipv4_ep1[] = {
{ IPv4(172, 16, 1, 5), 32, 2 },
{ IPv4(172, 16, 1, 6), 32, 2 },
{ IPv4(172, 16, 1, 7), 32, 3 },
{ IPv4(172, 16, 1, 8), 32, 3 },
{ IPv4(192, 168, 105, 0), 24, 0 },
{ IPv4(192, 168, 106, 0), 24, 0 },
{ IPv4(192, 168, 107, 0), 24, 1 },
{ IPv4(192, 168, 108, 0), 24, 1 },
{ IPv4(192, 168, 200, 0), 24, 0 },
{ IPv4(192, 168, 240, 0), 24, 2 },
{ IPv4(192, 168, 250, 0), 24, 0 }
};
void
rt_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
{
char name[PATH_MAX];
unsigned i;
int ret;
struct rte_lpm *lpm;
struct ipv4_route *rt;
char a, b, c, d;
unsigned nb_routes;
struct rte_lpm_config conf = { 0 };
if (ctx == NULL)
rte_exit(EXIT_FAILURE, "NULL context.\n");
if (ctx->rt_ipv4 != NULL)
rte_exit(EXIT_FAILURE, "Routing Table for socket %u already "
"initialized\n", socket_id);
printf("Creating Routing Table (RT) context with %u max routes\n",
RT_IPV4_MAX_RULES);
if (ep == 0) {
rt = rt_ipv4_ep0;
nb_routes = RTE_DIM(rt_ipv4_ep0);
} else if (ep == 1) {
rt = rt_ipv4_ep1;
nb_routes = RTE_DIM(rt_ipv4_ep1);
} else
rte_exit(EXIT_FAILURE, "Invalid EP value %u. Only 0 or 1 "
"supported.\n", ep);
/* create the LPM table */
snprintf(name, sizeof(name), "%s_%u", "rt_ipv4", socket_id);
conf.max_rules = RT_IPV4_MAX_RULES;
conf.number_tbl8s = RTE_LPM_TBL8_NUM_ENTRIES;
lpm = rte_lpm_create(name, socket_id, &conf);
if (lpm == NULL)
rte_exit(EXIT_FAILURE, "Unable to create LPM table "
"on socket %d\n", socket_id);
/* populate the LPM table */
for (i = 0; i < nb_routes; i++) {
ret = rte_lpm_add(lpm, rt[i].ip, rt[i].depth, rt[i].if_out);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Unable to add entry num %u to "
"LPM table on socket %d\n", i, socket_id);
uint32_t_to_char(rt[i].ip, &a, &b, &c, &d);
printf("LPM: Adding route %hhu.%hhu.%hhu.%hhu/%hhu (%hhu)\n",
a, b, c, d, rt[i].depth, rt[i].if_out);
}
ctx->rt_ipv4 = (struct rt_ctx *)lpm;
}

438
examples/ipsec-secgw/sa.c Normal file
View File

@ -0,0 +1,438 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Security Associations
*/
#include <netinet/ip.h>
#include <rte_memzone.h>
#include <rte_crypto.h>
#include <rte_cryptodev.h>
#include <rte_byteorder.h>
#include <rte_errno.h>
#include "ipsec.h"
#include "esp.h"
/* SAs EP0 Outbound */
const struct ipsec_sa sa_ep0_out[] = {
{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
0, 0, 4,
0, 0 },
};
/* SAs EP0 Inbound */
const struct ipsec_sa sa_ep0_in[] = {
{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
0, 0, 4,
0, 0 },
};
/* SAs EP1 Outbound */
const struct ipsec_sa sa_ep1_out[] = {
{ 5, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 6, 0, IPv4(172, 16, 2, 6), IPv4(172, 16, 1, 6),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 7, 0, IPv4(172, 16, 2, 7), IPv4(172, 16, 1, 7),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 8, 0, IPv4(172, 16, 2, 8), IPv4(172, 16, 1, 8),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 9, 0, IPv4(172, 16, 2, 5), IPv4(172, 16, 1, 5),
NULL, NULL,
esp4_tunnel_outbound_pre_crypto,
esp4_tunnel_outbound_post_crypto,
RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
0, 0, 4,
0, 0 },
};
/* SAs EP1 Inbound */
const struct ipsec_sa sa_ep1_in[] = {
{ 5, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 6, 0, IPv4(172, 16, 1, 6), IPv4(172, 16, 2, 6),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 7, 0, IPv4(172, 16, 1, 7), IPv4(172, 16, 2, 7),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 8, 0, IPv4(172, 16, 1, 8), IPv4(172, 16, 2, 8),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_AES_CBC, RTE_CRYPTO_AUTH_SHA1_HMAC,
12, 16, 16,
0, 0 },
{ 9, 0, IPv4(172, 16, 1, 5), IPv4(172, 16, 2, 5),
NULL, NULL,
esp4_tunnel_inbound_pre_crypto,
esp4_tunnel_inbound_post_crypto,
RTE_CRYPTO_CIPHER_NULL, RTE_CRYPTO_AUTH_NULL,
0, 0, 4,
0, 0 },
};
static uint8_t cipher_key[256] = "sixteenbytes key";
/* AES CBC xform */
const struct rte_crypto_sym_xform aescbc_enc_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_CIPHER,
.cipher = { RTE_CRYPTO_CIPHER_OP_ENCRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
.key = { cipher_key, 16 } }
};
const struct rte_crypto_sym_xform aescbc_dec_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_CIPHER,
.cipher = { RTE_CRYPTO_CIPHER_OP_DECRYPT, RTE_CRYPTO_CIPHER_AES_CBC,
.key = { cipher_key, 16 } }
};
static uint8_t auth_key[256] = "twentybytes hash key";
/* SHA1 HMAC xform */
const struct rte_crypto_sym_xform sha1hmac_gen_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_AUTH,
.auth = { RTE_CRYPTO_AUTH_OP_GENERATE, RTE_CRYPTO_AUTH_SHA1_HMAC,
.key = { auth_key, 20 }, 12, 0 }
};
const struct rte_crypto_sym_xform sha1hmac_verify_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_AUTH,
.auth = { RTE_CRYPTO_AUTH_OP_VERIFY, RTE_CRYPTO_AUTH_SHA1_HMAC,
.key = { auth_key, 20 }, 12, 0 }
};
/* AES CBC xform */
const struct rte_crypto_sym_xform null_cipher_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_CIPHER,
.cipher = { .algo = RTE_CRYPTO_CIPHER_NULL }
};
const struct rte_crypto_sym_xform null_auth_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_AUTH,
.auth = { .algo = RTE_CRYPTO_AUTH_NULL }
};
struct sa_ctx {
struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
struct {
struct rte_crypto_sym_xform a;
struct rte_crypto_sym_xform b;
} xf[IPSEC_SA_MAX_ENTRIES];
};
static struct sa_ctx *
sa_ipv4_create(const char *name, int socket_id)
{
char s[PATH_MAX];
struct sa_ctx *sa_ctx;
unsigned mz_size;
const struct rte_memzone *mz;
snprintf(s, sizeof(s), "%s_%u", name, socket_id);
/* Create SA array table */
printf("Creating SA context with %u maximum entries\n",
IPSEC_SA_MAX_ENTRIES);
mz_size = sizeof(struct sa_ctx);
mz = rte_memzone_reserve(s, mz_size, socket_id,
RTE_MEMZONE_1GB | RTE_MEMZONE_SIZE_HINT_ONLY);
if (mz == NULL) {
printf("Failed to allocate SA DB memory\n");
rte_errno = -ENOMEM;
return NULL;
}
sa_ctx = (struct sa_ctx *)mz->addr;
return sa_ctx;
}
static int
sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
unsigned nb_entries, unsigned inbound)
{
struct ipsec_sa *sa;
unsigned i, idx;
for (i = 0; i < nb_entries; i++) {
idx = SPI2IDX(entries[i].spi);
sa = &sa_ctx->sa[idx];
if (sa->spi != 0) {
printf("Index %u already in use by SPI %u\n",
idx, sa->spi);
return -EINVAL;
}
*sa = entries[i];
sa->src = rte_cpu_to_be_32(sa->src);
sa->dst = rte_cpu_to_be_32(sa->dst);
if (inbound) {
if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
sa_ctx->xf[idx].a = null_auth_xf;
sa_ctx->xf[idx].b = null_cipher_xf;
} else {
sa_ctx->xf[idx].a = sha1hmac_verify_xf;
sa_ctx->xf[idx].b = aescbc_dec_xf;
}
} else { /* outbound */
if (sa->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
sa_ctx->xf[idx].a = null_cipher_xf;
sa_ctx->xf[idx].b = null_auth_xf;
} else {
sa_ctx->xf[idx].a = aescbc_enc_xf;
sa_ctx->xf[idx].b = sha1hmac_gen_xf;
}
}
sa_ctx->xf[idx].a.next = &sa_ctx->xf[idx].b;
sa_ctx->xf[idx].b.next = NULL;
sa->xforms = &sa_ctx->xf[idx].a;
}
return 0;
}
static inline int
sa_out_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
unsigned nb_entries)
{
return sa_add_rules(sa_ctx, entries, nb_entries, 0);
}
static inline int
sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
unsigned nb_entries)
{
return sa_add_rules(sa_ctx, entries, nb_entries, 1);
}
void
sa_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
{
const struct ipsec_sa *sa_out_entries, *sa_in_entries;
unsigned nb_out_entries, nb_in_entries;
const char *name;
if (ctx == NULL)
rte_exit(EXIT_FAILURE, "NULL context.\n");
if (ctx->sa_ipv4_in != NULL)
rte_exit(EXIT_FAILURE, "Inbound SA DB for socket %u already "
"initialized\n", socket_id);
if (ctx->sa_ipv4_out != NULL)
rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
"initialized\n", socket_id);
if (ep == 0) {
sa_out_entries = sa_ep0_out;
nb_out_entries = RTE_DIM(sa_ep0_out);
sa_in_entries = sa_ep0_in;
nb_in_entries = RTE_DIM(sa_ep0_in);
} else if (ep == 1) {
sa_out_entries = sa_ep1_out;
nb_out_entries = RTE_DIM(sa_ep1_out);
sa_in_entries = sa_ep1_in;
nb_in_entries = RTE_DIM(sa_ep1_in);
} else
rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
"Only 0 or 1 supported.\n", ep);
name = "sa_ipv4_in";
ctx->sa_ipv4_in = sa_ipv4_create(name, socket_id);
if (ctx->sa_ipv4_in == NULL)
rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
"in socket %d\n", rte_errno, name, socket_id);
name = "sa_ipv4_out";
ctx->sa_ipv4_out = sa_ipv4_create(name, socket_id);
if (ctx->sa_ipv4_out == NULL)
rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
"in socket %d\n", rte_errno, name, socket_id);
sa_in_add_rules(ctx->sa_ipv4_in, sa_in_entries, nb_in_entries);
sa_out_add_rules(ctx->sa_ipv4_out, sa_out_entries, nb_out_entries);
}
int
inbound_sa_check(struct sa_ctx *sa_ctx, struct rte_mbuf *m, uint32_t sa_idx)
{
struct ipsec_mbuf_metadata *priv;
priv = RTE_PTR_ADD(m, sizeof(struct rte_mbuf));
return (sa_ctx->sa[sa_idx].spi == priv->sa->spi);
}
void
inbound_sa_lookup(struct sa_ctx *sa_ctx, struct rte_mbuf *pkts[],
struct ipsec_sa *sa[], uint16_t nb_pkts)
{
unsigned i;
uint32_t *src, spi;
for (i = 0; i < nb_pkts; i++) {
spi = rte_pktmbuf_mtod_offset(pkts[i], struct esp_hdr *,
sizeof(struct ip))->spi;
if (spi == INVALID_SPI)
continue;
sa[i] = &sa_ctx->sa[SPI2IDX(spi)];
if (spi != sa[i]->spi) {
sa[i] = NULL;
continue;
}
src = rte_pktmbuf_mtod_offset(pkts[i], uint32_t *,
offsetof(struct ip, ip_src));
if ((sa[i]->src != *src) || (sa[i]->dst != *(src + 1)))
sa[i] = NULL;
}
}
void
outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
struct ipsec_sa *sa[], uint16_t nb_pkts)
{
unsigned i;
for (i = 0; i < nb_pkts; i++)
sa[i] = &sa_ctx->sa[sa_idx[i]];
}

364
examples/ipsec-secgw/sp.c Normal file
View File

@ -0,0 +1,364 @@
/*-
* BSD LICENSE
*
* Copyright(c) 2016 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Security Policies
*/
#include <netinet/ip.h>
#include <rte_acl.h>
#include "ipsec.h"
#define MAX_ACL_RULE_NUM 1000
/*
* Rule and trace formats definitions.
*/
enum {
PROTO_FIELD_IPV4,
SRC_FIELD_IPV4,
DST_FIELD_IPV4,
SRCP_FIELD_IPV4,
DSTP_FIELD_IPV4,
NUM_FIELDS_IPV4
};
/*
* That effectively defines order of IPV4 classifications:
* - PROTO
* - SRC IP ADDRESS
* - DST IP ADDRESS
* - PORTS (SRC and DST)
*/
enum {
RTE_ACL_IPV4_PROTO,
RTE_ACL_IPV4_SRC,
RTE_ACL_IPV4_DST,
RTE_ACL_IPV4_PORTS,
RTE_ACL_IPV4_NUM
};
struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
{
.type = RTE_ACL_FIELD_TYPE_BITMASK,
.size = sizeof(uint8_t),
.field_index = PROTO_FIELD_IPV4,
.input_index = RTE_ACL_IPV4_PROTO,
.offset = 0,
},
{
.type = RTE_ACL_FIELD_TYPE_MASK,
.size = sizeof(uint32_t),
.field_index = SRC_FIELD_IPV4,
.input_index = RTE_ACL_IPV4_SRC,
.offset = offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p)
},
{
.type = RTE_ACL_FIELD_TYPE_MASK,
.size = sizeof(uint32_t),
.field_index = DST_FIELD_IPV4,
.input_index = RTE_ACL_IPV4_DST,
.offset = offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p)
},
{
.type = RTE_ACL_FIELD_TYPE_RANGE,
.size = sizeof(uint16_t),
.field_index = SRCP_FIELD_IPV4,
.input_index = RTE_ACL_IPV4_PORTS,
.offset = sizeof(struct ip) - offsetof(struct ip, ip_p)
},
{
.type = RTE_ACL_FIELD_TYPE_RANGE,
.size = sizeof(uint16_t),
.field_index = DSTP_FIELD_IPV4,
.input_index = RTE_ACL_IPV4_PORTS,
.offset = sizeof(struct ip) - offsetof(struct ip, ip_p) +
sizeof(uint16_t)
},
};
RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ipv4_defs));
const struct acl4_rules acl4_rules_in[] = {
{
.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 105, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 106, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 107, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 108, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 200, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 250, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
}
};
const struct acl4_rules acl4_rules_out[] = {
{
.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 115, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 2},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 116, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(7), .category_mask = 1, .priority = 3},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 117, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(8), .category_mask = 1, .priority = 4},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 118, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(9), .category_mask = 1, .priority = 5},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 210, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = BYPASS, .category_mask = 1, .priority = 6},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 240, 0),
.mask_range.u32 = 24,},
/* source port */
.field[3] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[4] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
}
};
static void
print_one_ipv4_rule(const struct acl4_rules *rule, int extra)
{
unsigned char a, b, c, d;
uint32_t_to_char(rule->field[SRC_FIELD_IPV4].value.u32,
&a, &b, &c, &d);
printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
rule->field[SRC_FIELD_IPV4].mask_range.u32);
uint32_t_to_char(rule->field[DST_FIELD_IPV4].value.u32,
&a, &b, &c, &d);
printf("%hhu.%hhu.%hhu.%hhu/%u ", a, b, c, d,
rule->field[DST_FIELD_IPV4].mask_range.u32);
printf("%hu : %hu %hu : %hu 0x%hhx/0x%hhx ",
rule->field[SRCP_FIELD_IPV4].value.u16,
rule->field[SRCP_FIELD_IPV4].mask_range.u16,
rule->field[DSTP_FIELD_IPV4].value.u16,
rule->field[DSTP_FIELD_IPV4].mask_range.u16,
rule->field[PROTO_FIELD_IPV4].value.u8,
rule->field[PROTO_FIELD_IPV4].mask_range.u8);
if (extra)
printf("0x%x-0x%x-0x%x ",
rule->data.category_mask,
rule->data.priority,
rule->data.userdata);
}
static inline void
dump_ipv4_rules(const struct acl4_rules *rule, int num, int extra)
{
int i;
for (i = 0; i < num; i++, rule++) {
printf("\t%d:", i + 1);
print_one_ipv4_rule(rule, extra);
printf("\n");
}
}
static struct rte_acl_ctx *
acl4_init(const char *name, int socketid, const struct acl4_rules *rules,
unsigned rules_nb)
{
char s[PATH_MAX];
struct rte_acl_param acl_param;
struct rte_acl_config acl_build_param;
struct rte_acl_ctx *ctx;
printf("Creating SP context with %u max rules\n", MAX_ACL_RULE_NUM);
memset(&acl_param, 0, sizeof(acl_param));
/* Create ACL contexts */
snprintf(s, sizeof(s), "%s_%d", name, socketid);
printf("IPv4 %s entries [%u]:\n", s, rules_nb);
dump_ipv4_rules(rules, rules_nb, 1);
acl_param.name = s;
acl_param.socket_id = socketid;
acl_param.rule_size = RTE_ACL_RULE_SZ(RTE_DIM(ipv4_defs));
acl_param.max_rule_num = MAX_ACL_RULE_NUM;
ctx = rte_acl_create(&acl_param);
if (ctx == NULL)
rte_exit(EXIT_FAILURE, "Failed to create ACL context\n");
if (rte_acl_add_rules(ctx, (const struct rte_acl_rule *)rules,
rules_nb) < 0)
rte_exit(EXIT_FAILURE, "add rules failed\n");
/* Perform builds */
memset(&acl_build_param, 0, sizeof(acl_build_param));
acl_build_param.num_categories = DEFAULT_MAX_CATEGORIES;
acl_build_param.num_fields = RTE_DIM(ipv4_defs);
memcpy(&acl_build_param.defs, ipv4_defs, sizeof(ipv4_defs));
if (rte_acl_build(ctx, &acl_build_param) != 0)
rte_exit(EXIT_FAILURE, "Failed to build ACL trie\n");
rte_acl_dump(ctx);
return ctx;
}
void
sp_init(struct socket_ctx *ctx, int socket_id, unsigned ep)
{
const char *name;
const struct acl4_rules *rules_out, *rules_in;
unsigned nb_out_rules, nb_in_rules;
if (ctx == NULL)
rte_exit(EXIT_FAILURE, "NULL context.\n");
if (ctx->sp_ipv4_in != NULL)
rte_exit(EXIT_FAILURE, "Inbound SP DB for socket %u already "
"initialized\n", socket_id);
if (ctx->sp_ipv4_out != NULL)
rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
"initialized\n", socket_id);
if (ep == 0) {
rules_out = acl4_rules_in;
nb_out_rules = RTE_DIM(acl4_rules_in);
rules_in = acl4_rules_out;
nb_in_rules = RTE_DIM(acl4_rules_out);
} else if (ep == 1) {
rules_out = acl4_rules_out;
nb_out_rules = RTE_DIM(acl4_rules_out);
rules_in = acl4_rules_in;
nb_in_rules = RTE_DIM(acl4_rules_in);
} else
rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
"Only 0 or 1 supported.\n", ep);
name = "sp_ipv4_in";
ctx->sp_ipv4_in = (struct sp_ctx *)acl4_init(name, socket_id,
rules_in, nb_in_rules);
name = "sp_ipv4_out";
ctx->sp_ipv4_out = (struct sp_ctx *)acl4_init(name, socket_id,
rules_out, nb_out_rules);
}