examples/ipsec-secgw: support configuration file

This patch adds the configuration file support to ipsec_secgw
sample application. Instead of hard-coded rules, the users can
specify their own SP, SA, and routing rules in the configuration
file. A command line option "-f" is added to pass the
configuration file location to the application.

Configuration item formats:

SP rule format:
sp <ip_ver> <dir> esp <action> <priority> <src_ip> <dst_ip> \
<proto> <sport> <dport>

SA rule format:
sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key> \
<mode> <src_ip> <dst_ip>

Routing rule format:
rt <ip_ver> <src_ip> <dst_ip> <port>

Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
Acked-by: Sergio Gonzalez Monroy <sergio.gonzalez.monroy@intel.com>
This commit is contained in:
Fan Zhang 2016-09-21 13:05:18 +01:00 committed by Pablo de Lara
parent 77debbbfdf
commit 0d547ed037
11 changed files with 2392 additions and 1314 deletions

View File

@ -78,6 +78,10 @@ New Features
* C3XXX device
* C62XX device
* **Updated the IPsec example with following support:**
* configuration file
Resolved Issues
---------------

View File

@ -122,7 +122,7 @@ The application has a number of command line options::
-p PORTMASK -P -u PORTMASK
--config (port,queue,lcore)[,(port,queue,lcore]
--single-sa SAIDX
--ep0|--ep1
-f CONFIG_FILE_PATH
Where:
@ -142,14 +142,11 @@ Where:
on both Inbound and Outbound. This option is meant for debugging/performance
purposes.
* ``--ep0``: configure the app as Endpoint 0.
* ``-f CONFIG_FILE_PATH``: the full path of text-based file containing all
configuration items for running the application (See Configuration file
syntax section below). ``-f CONFIG_FILE_PATH`` **must** be specified.
**ONLY** the UNIX format configuration file is accepted.
* ``--ep1``: configure the app as Endpoint 1.
Either one of ``--ep0`` or ``--ep1`` **must** be specified.
The main purpose of these options is to easily configure two systems
back-to-back that would forward traffic through an IPsec tunnel (see
:ref:`figure_ipsec_endpoints`).
The mapping of lcores to port/queues is similar to other l3fwd applications.
@ -157,7 +154,8 @@ For example, given the following command line::
./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 \
--config="(0,0,20),(1,0,20),(2,0,21),(3,0,21)" \
-f /path/to/config_file \
where each options means:
@ -194,8 +192,12 @@ where each options means:
| | | | |
+----------+-----------+-----------+---------------------------------------+
* The ``--ep0`` options configures the app with a given set of SP, SA and Routing
entries as explained below in more detail.
* The ``-f /path/to/config_file`` option enables the application read and
parse the configuration file specified, and configures the application
with a given set of SP, SA and Routing entries accordingly. The syntax of
the configuration file will be explained below in more detail. Please
**note** the parser only accepts UNIX format text file. Other formats
such as DOS/MAC format will cause a parse error.
Refer to the *DPDK Getting Started Guide* for general information on running
applications and the Environment Abstraction Layer (EAL) options.
@ -219,496 +221,357 @@ For example, something like the following command line:
--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
-f sample.cfg
Configurations
--------------
The following sections provide some details on the default values used to
initialize the SP, SA and Routing tables.
Currently all configuration information is hard coded into the application.
The following image illustrate a few of the concepts regarding IPSec, such
as protected/unprotected and inbound/outbound traffic, from the point of
view of two back-to-back endpoints:
.. _figure_ipsec_endpoints:
.. figure:: img/ipsec_endpoints.*
IPSec Inbound/Outbound traffic
Note that the above image only displays unidirectional traffic per port
for illustration purposes.
The application supports bidirectional traffic on all ports,
The following sections provide the syntax of configurations to initialize
your SP, SA and Routing tables.
Configurations shall be specified in the configuration file to be passed to
the application. The file is then parsed by the application. The successful
parsing will result in the appropriate rules being applied to the tables
accordingly.
Security Policy Initialization
Configuration File Syntax
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
The application parsers the rules specified in the configuration file and
passes them to the ACL table, and replicates them per socket in use.
Following are the default rules which show only the relevant information,
assuming ANY value is valid for the fields not mentioned (src ip, proto,
src/dst ports).
Following are the configuration file syntax.
.. _table_ipsec_endpoint_outbound_sp:
General rule syntax
^^^^^^^^^^^^^^^^^^^
.. table:: Endpoint 0 Outbound Security Policies
The parse treats one line in the configuration file as one configuration
item (unless the line concatenation symbol exists). Every configuration
item shall follow the syntax of either SP, SA, or Routing rules specified
below.
+-----------------------------------+------------+
| **Dst** | **SA idx** |
| | |
+-----------------------------------+------------+
| 192.168.105.0/24 | 5 |
| | |
+-----------------------------------+------------+
| 192.168.106.0/24 | 6 |
| | |
+-----------------------------------+------------+
| 192.168.175.0/24 | 10 |
| | |
+-----------------------------------+------------+
| 192.168.176.0/24 | 11 |
| | |
+-----------------------------------+------------+
| 192.168.200.0/24 | 15 |
| | |
+-----------------------------------+------------+
| 192.168.201.0/24 | 16 |
| | |
+-----------------------------------+------------+
| 192.168.55.0/24 | 25 |
| | |
+-----------------------------------+------------+
| 192.168.56.0/24 | 26 |
| | |
+-----------------------------------+------------+
| 192.168.240.0/24 | BYPASS |
| | |
+-----------------------------------+------------+
| 192.168.241.0/24 | BYPASS |
| | |
+-----------------------------------+------------+
| 0:0:0:0:5555:5555:0:0/96 | 5 |
| | |
+-----------------------------------+------------+
| 0:0:0:0:6666:6666:0:0/96 | 6 |
| | |
+-----------------------------------+------------+
| 0:0:1111:1111:0:0:0:0/96 | 10 |
| | |
+-----------------------------------+------------+
| 0:0:1111:1111:1111:1111:0:0/96 | 11 |
| | |
+-----------------------------------+------------+
| 0:0:0:0:aaaa:aaaa:0:0/96 | 25 |
| | |
+-----------------------------------+------------+
| 0:0:0:0:bbbb:bbbb:0:0/96 | 26 |
| | |
+-----------------------------------+------------+
The configuration parser supports the following special symbols:
.. _table_ipsec_endpoint_inbound_sp:
* Comment symbol **#**. Any character from this symbol to the end of
line is treated as comment and will not be parsed.
.. table:: Endpoint 0 Inbound Security Policies
+-----------------------------------+------------+
| **Dst** | **SA idx** |
| | |
+-----------------------------------+------------+
| 192.168.115.0/24 | 105 |
| | |
+-----------------------------------+------------+
| 192.168.116.0/24 | 106 |
| | |
+-----------------------------------+------------+
| 192.168.185.0/24 | 110 |
| | |
+-----------------------------------+------------+
| 192.168.186.0/24 | 111 |
| | |
+-----------------------------------+------------+
| 192.168.210.0/24 | 115 |
| | |
+-----------------------------------+------------+
| 192.168.211.0/24 | 116 |
| | |
+-----------------------------------+------------+
| 192.168.65.0/24 | 125 |
| | |
+-----------------------------------+------------+
| 192.168.66.0/24 | 126 |
| | |
+-----------------------------------+------------+
| 192.168.245.0/24 | BYPASS |
| | |
+-----------------------------------+------------+
| 192.168.246.0/24 | BYPASS |
| | |
+-----------------------------------+------------+
| ffff:0:0:0:5555:5555:0:0/96 | 105 |
| | |
+-----------------------------------+------------+
| ffff:0:0:0:6666:6666:0:0/96 | 106 |
| | |
+-----------------------------------+------------+
| ffff:0:1111:1111:0:0:0:0/96 | 110 |
| | |
+-----------------------------------+------------+
| ffff:0:1111:1111:1111:1111:0:0/96 | 111 |
| | |
+-----------------------------------+------------+
| ffff:0:0:0:aaaa:aaaa:0:0/96 | 125 |
| | |
+-----------------------------------+------------+
| ffff:0:0:0:bbbb:bbbb:0:0/96 | 126 |
| | |
+-----------------------------------+------------+
For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
entries are set as Outbound and vice versa.
* Line concatenation symbol **\\**. This symbol shall be placed in the end
of the line to be concatenated to the line below. Multiple lines'
concatenation is supported.
Security Association Initialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SP rule syntax
^^^^^^^^^^^^^^
The SAs are kept in a array table.
The SP rule syntax is shown as follows:
For Inbound, the SPI is used as index modulo 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.
.. code-block:: console
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.
The following are the default values:
.. _table_ipsec_endpoint_outbound_sa:
.. table:: Endpoint 0 Outbound Security Associations
+---------+----------+------------+-----------+----------------+----------------+
| **SPI** | **Mode** | **Cipher** | **Auth** | **Tunnel src** | **Tunnel dst** |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 5 | Tunnel | AES-CBC | HMAC-SHA1 | 172.16.1.5 | 172.16.2.5 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 6 | Tunnel | AES-CBC | HMAC-SHA1 | 172.16.1.6 | 172.16.2.6 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 10 | Trans | AES-CBC | HMAC-SHA1 | N/A | N/A |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 11 | Trans | AES-CBC | HMAC-SHA1 | N/A | N/A |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 15 | Tunnel | NULL | NULL | 172.16.1.5 | 172.16.2.5 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 16 | Tunnel | NULL | NULL | 172.16.1.6 | 172.16.2.6 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 25 | Tunnel | AES-CBC | HMAC-SHA1 | 1111:1111: | 2222:2222: |
| | | | | 1111:1111: | 2222:2222: |
| | | | | 1111:1111: | 2222:2222: |
| | | | | 1111:5555 | 2222:5555 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 26 | Tunnel | AES-CBC | HMAC-SHA1 | 1111:1111: | 2222:2222: |
| | | | | 1111:1111: | 2222:2222: |
| | | | | 1111:1111: | 2222:2222: |
| | | | | 1111:6666 | 2222:6666 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
.. _table_ipsec_endpoint_inbound_sa:
.. table:: Endpoint 0 Inbound Security Associations
+---------+----------+------------+-----------+----------------+----------------+
| **SPI** | **Mode** | **Cipher** | **Auth** | **Tunnel src** | **Tunnel dst** |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 105 | Tunnel | AES-CBC | HMAC-SHA1 | 172.16.2.5 | 172.16.1.5 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 106 | Tunnel | AES-CBC | HMAC-SHA1 | 172.16.2.6 | 172.16.1.6 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 110 | Trans | AES-CBC | HMAC-SHA1 | N/A | N/A |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 111 | Trans | AES-CBC | HMAC-SHA1 | N/A | N/A |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 115 | Tunnel | NULL | NULL | 172.16.2.5 | 172.16.1.5 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 116 | Tunnel | NULL | NULL | 172.16.2.6 | 172.16.1.6 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 125 | Tunnel | AES-CBC | HMAC-SHA1 | 2222:2222: | 1111:1111: |
| | | | | 2222:2222: | 1111:1111: |
| | | | | 2222:2222: | 1111:1111: |
| | | | | 2222:5555 | 1111:5555 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
| 126 | Tunnel | AES-CBC | HMAC-SHA1 | 2222:2222: | 1111:1111: |
| | | | | 2222:2222: | 1111:1111: |
| | | | | 2222:2222: | 1111:1111: |
| | | | | 2222:6666 | 1111:6666 |
| | | | | | |
+---------+----------+------------+-----------+----------------+----------------+
For Endpoint 1, we use the same policies in reverse, meaning the Inbound SP
entries are set as Outbound and vice versa.
sp <ip_ver> <dir> esp <action> <priority> <src_ip> <dst_ip>
<proto> <sport> <dport>
Routing Initialization
~~~~~~~~~~~~~~~~~~~~~~
where each options means:
The Routing is implemented using an LPM table.
``<ip_ver>``
Following default values:
* IP protocol version
.. _table_ipsec_endpoint_outbound_routing:
* Optional: No
.. table:: Endpoint 0 Routing Table
* Available options:
+------------------+----------+
| **Dst addr** | **Port** |
| | |
+------------------+----------+
| 172.16.2.5/32 | 0 |
| | |
+------------------+----------+
| 172.16.2.6/32 | 1 |
| | |
+------------------+----------+
| 192.168.175.0/24 | 0 |
| | |
+------------------+----------+
| 192.168.176.0/24 | 1 |
| | |
+------------------+----------+
| 192.168.240.0/24 | 0 |
| | |
+------------------+----------+
| 192.168.241.0/24 | 1 |
| | |
+------------------+----------+
| 192.168.115.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.116.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.65.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.66.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.185.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.186.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.210.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.211.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.245.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.246.0/24 | 3 |
| | |
+------------------+----------+
| 2222:2222: | 0 |
| 2222:2222: | |
| 2222:2222: | |
| 2222:5555/116 | |
| | |
+------------------+----------+
| 2222:2222: | 1 |
| 2222:2222: | |
| 2222:2222: | |
| 2222:6666/116 | |
| | |
+------------------+----------+
| 0000:0000: | 0 |
| 1111:1111: | |
| 0000:0000: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
| 0000:0000: | 1 |
| 1111:1111: | |
| 1111:1111: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
| ffff:0000: | 2 |
| 0000:0000: | |
| aaaa:aaaa: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| ffff:0000: | 3 |
| 0000:0000: | |
| bbbb:bbbb: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| ffff:0000: | 2 |
| 0000:0000: | |
| 5555:5555: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| ffff:0000: | 3 |
| 0000:0000: | |
| 6666:6666: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| ffff:0000: | 2 |
| 1111:1111: | |
| 0000:0000: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
| ffff:0000: | 3 |
| 1111:1111: | |
| 1111:1111: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
* *ipv4*: IP protocol version 4
* *ipv6*: IP protocol version 6
.. _table_ipsec_endpoint_inbound_routing:
``<dir>``
.. table:: Endpoint 1 Routing Table
* The traffic direction
+------------------+----------+
| **Dst addr** | **Port** |
| | |
+------------------+----------+
| 172.16.1.5/32 | 0 |
| | |
+------------------+----------+
| 172.16.1.6/32 | 1 |
| | |
+------------------+----------+
| 192.168.185.0/24 | 0 |
| | |
+------------------+----------+
| 192.168.186.0/24 | 1 |
| | |
+------------------+----------+
| 192.168.245.0/24 | 0 |
| | |
+------------------+----------+
| 192.168.246.0/24 | 1 |
| | |
+------------------+----------+
| 192.168.105.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.106.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.55.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.56.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.175.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.176.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.200.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.201.0/24 | 3 |
| | |
+------------------+----------+
| 192.168.240.0/24 | 2 |
| | |
+------------------+----------+
| 192.168.241.0/24 | 3 |
| | |
+------------------+----------+
| 1111:1111: | 0 |
| 1111:1111: | |
| 1111:1111: | |
| 1111:5555/116 | |
| | |
+------------------+----------+
| 1111:1111: | 1 |
| 1111:1111: | |
| 1111:1111: | |
| 1111:6666/116 | |
| | |
+------------------+----------+
| ffff:0000: | 0 |
| 1111:1111: | |
| 0000:0000: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
| ffff:0000: | 1 |
| 1111:1111: | |
| 1111:1111: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
| 0000:0000: | 2 |
| 0000:0000: | |
| aaaa:aaaa: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| 0000:0000: | 3 |
| 0000:0000: | |
| bbbb:bbbb: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| 0000:0000: | 2 |
| 0000:0000: | |
| 5555:5555: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| 0000:0000: | 3 |
| 0000:0000: | |
| 6666:6666: | |
| 0000:0/116 | |
| | |
+------------------+----------+
| 0000:0000: | 2 |
| 1111:1111: | |
| 0000:0000: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
| 0000:0000: | 3 |
| 1111:1111: | |
| 1111:1111: | |
| 0000:0000/116 | |
| | |
+------------------+----------+
* Optional: No
* Available options:
* *in*: inbound traffic
* *out*: outbound traffic
``<action>``
* IPsec action
* Optional: No
* Available options:
* *protect <SA_idx>*: the specified traffic is protected by SA rule
with id SA_idx
* *bypass*: the specified traffic traffic is bypassed
* *discard*: the specified traffic is discarded
``<priority>``
* Rule priority
* Optional: Yes, default priority 0 will be used
* Syntax: *pri <id>*
``<src_ip>``
* The source IP address and mask
* Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
* Syntax:
* *src X.X.X.X/Y* for IPv4
* *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
``<dst_ip>``
* The destination IP address and mask
* Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
* Syntax:
* *dst X.X.X.X/Y* for IPv4
* *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
``<proto>``
* The protocol start and end range
* Optional: yes, default range of 0 to 0 will be used
* Syntax: *proto X:Y*
``<sport>``
* The source port start and end range
* Optional: yes, default range of 0 to 0 will be used
* Syntax: *sport X:Y*
``<dport>``
* The destination port start and end range
* Optional: yes, default range of 0 to 0 will be used
* Syntax: *dport X:Y*
Example SP rules:
.. code-block:: console
sp ipv4 out esp protect 105 pri 1 dst 192.168.115.0/24 sport 0:65535 \
dport 0:65535
sp ipv6 in esp bypass pri 1 dst 0000:0000:0000:0000:5555:5555:\
0000:0000/96 sport 0:65535 dport 0:65535
SA rule syntax
^^^^^^^^^^^^^^
The successfully parsed SA rules will be stored in an array table.
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.
The SA rule syntax is shown as follows:
.. code-block:: console
sa <dir> <spi> <cipher_algo> <cipher_key> <auth_algo> <auth_key>
<mode> <src_ip> <dst_ip>
where each options means:
``<dir>``
* The traffic direction
* Optional: No
* Available options:
* *in*: inbound traffic
* *out*: outbound traffic
``<spi>``
* The SPI number
* Optional: No
* Syntax: unsigned integer number
``<cipher_algo>``
* Cipher algorithm
* Optional: No
* Available options:
* *null*: NULL algorithm
* *aes-128-cbc*: AES-CBC 128-bit algorithm
* Syntax: *cipher_algo <your algorithm>*
``<cipher_key>``
* Cipher key, NOT available when 'null' algorithm is used
* Optional: No, must followed by <cipher_algo> option
* Syntax: Hexadecimal bytes (0x0-0xFF) concatenate by colon symbol ':'.
The number of bytes should be as same as the specified cipher algorithm
key size.
For example: *cipher_key A1:B2:C3:D4:A1:B2:C3:D4:A1:B2:C3:D4:
A1:B2:C3:D4*
``<auth_algo>``
* Authentication algorithm
* Optional: No
* Available options:
* *null*: NULL algorithm
* *sha1-hmac*: HMAC SHA1 algorithm
``<auth_key>``
* Authentication key, NOT available when 'null' algorithm is used
* Optional: No, must followed by <auth_algo> option
* Syntax: Hexadecimal bytes (0x0-0xFF) concatenate by colon symbol ':'.
The number of bytes should be as same as the specified authentication
algorithm key size.
For example: *auth_key A1:B2:C3:D4:A1:B2:C3:D4:A1:B2:C3:D4:A1:B2:C3:D4:
A1:B2:C3:D4*
``<mode>``
* The operation mode
* Optional: No
* Available options:
* *ipv4-tunnel*: Tunnel mode for IPv4 packets
* *ipv6-tunnel*: Tunnel mode for IPv6 packets
* *transport*: transport mode
* Syntax: mode XXX
``<src_ip>``
* The source IP address. This option is not available when
transport mode is used
* Optional: Yes, default address 0.0.0.0 will be used
* Syntax:
* *src X.X.X.X* for IPv4
* *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX* for IPv6
``<dst_ip>``
* The destination IP address. This option is not available when
transport mode is used
* Optional: Yes, default address 0.0.0.0 will be used
* Syntax:
* *dst X.X.X.X* for IPv4
* *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX* for IPv6
Example SA rules:
.. code-block:: console
sa out 5 cipher_algo null auth_algo null mode ipv4-tunnel \
src 172.16.1.5 dst 172.16.2.5
sa out 25 cipher_algo aes-128-cbc \
cipher_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3 \
auth_algo sha1-hmac \
auth_key c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3:c3 \
mode ipv6-tunnel \
src 1111:1111:1111:1111:1111:1111:1111:5555 \
dst 2222:2222:2222:2222:2222:2222:2222:5555
Routing rule syntax
^^^^^^^^^^^^^^^^^^^
The Routing rule syntax is shown as follows:
.. code-block:: console
rt <ip_ver> <src_ip> <dst_ip> <port>
where each options means:
``<ip_ver>``
* IP protocol version
* Optional: No
* Available options:
* *ipv4*: IP protocol version 4
* *ipv6*: IP protocol version 6
``<src_ip>``
* The source IP address and mask
* Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
* Syntax:
* *src X.X.X.X/Y* for IPv4
* *src XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
``<dst_ip>``
* The destination IP address and mask
* Optional: Yes, default address 0.0.0.0 and mask of 0 will be used
* Syntax:
* *dst X.X.X.X/Y* for IPv4
* *dst XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/Y* for IPv6
``<port>``
* The traffic output port id
* Optional: yes, default output port 0 will be used
* Syntax: *port X*
Example SP rules:
.. code-block:: console
rt ipv4 dst 172.16.1.5/32 port 0
rt ipv6 dst 1111:1111:1111:1111:1111:1111:1111:5555/116 port 0

View File

@ -53,6 +53,7 @@ endif
#
# all source are stored in SRCS-y
#
SRCS-y += parser.c
SRCS-y += ipsec.c
SRCS-y += esp.c
SRCS-y += sp4.c

View File

@ -72,6 +72,7 @@
#include <rte_cryptodev.h>
#include "ipsec.h"
#include "parser.h"
#define RTE_LOGTYPE_IPSEC RTE_LOGTYPE_USER1
@ -88,8 +89,6 @@
#define OPTION_CONFIG "config"
#define OPTION_SINGLE_SA "single-sa"
#define OPTION_EP0 "ep0"
#define OPTION_EP1 "ep1"
#define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */
@ -158,7 +157,6 @@ static uint32_t enabled_port_mask;
static uint32_t unprotected_port_mask;
static int32_t promiscuous_on = 1;
static int32_t numa_on = 1; /**< NUMA is enabled by default. */
static int32_t ep = -1; /**< Endpoint configuration (0 or 1) */
static uint32_t nb_lcores;
static uint32_t single_sa;
static uint32_t single_sa_idx;
@ -838,7 +836,7 @@ print_usage(const char *prgname)
{
printf("%s [EAL options] -- -p PORTMASK -P -u PORTMASK"
" --"OPTION_CONFIG" (port,queue,lcore)[,(port,queue,lcore]"
" --single-sa SAIDX --ep0|--ep1\n"
" --single-sa SAIDX -f CONFIG_FILE\n"
" -p PORTMASK: hexadecimal bitmask of ports to configure\n"
" -P : enable promiscuous mode\n"
" -u PORTMASK: hexadecimal bitmask of unprotected ports\n"
@ -846,8 +844,8 @@ print_usage(const char *prgname)
"rx queues configuration\n"
" --single-sa SAIDX: use single SA index for outbound, "
"bypassing the SP\n"
" --ep0: Configure as Endpoint 0\n"
" --ep1: Configure as Endpoint 1\n", prgname);
" -f CONFIG_FILE: Configuration file path\n",
prgname);
}
static int32_t
@ -960,18 +958,6 @@ parse_args_long_options(struct option *lgopts, int32_t option_index)
}
}
if (__STRNCMP(optname, OPTION_EP0)) {
printf("endpoint 0\n");
ep = 0;
ret = 0;
}
if (__STRNCMP(optname, OPTION_EP1)) {
printf("endpoint 1\n");
ep = 1;
ret = 0;
}
return ret;
}
#undef __STRNCMP
@ -986,14 +972,13 @@ parse_args(int32_t argc, char **argv)
static struct option lgopts[] = {
{OPTION_CONFIG, 1, 0, 0},
{OPTION_SINGLE_SA, 1, 0, 0},
{OPTION_EP0, 0, 0, 0},
{OPTION_EP1, 0, 0, 0},
{NULL, 0, 0, 0}
};
int32_t f_present = 0;
argvopt = argv;
while ((opt = getopt_long(argc, argvopt, "p:Pu:",
while ((opt = getopt_long(argc, argvopt, "p:Pu:f:",
lgopts, &option_index)) != EOF) {
switch (opt) {
@ -1017,6 +1002,21 @@ parse_args(int32_t argc, char **argv)
return -1;
}
break;
case 'f':
if (f_present == 1) {
printf("\"-f\" option present more than "
"once!\n");
print_usage(prgname);
return -1;
}
if (parse_cfg_file(optarg) < 0) {
printf("parsing file \"%s\" failed\n",
optarg);
print_usage(prgname);
return -1;
}
f_present = 1;
break;
case 0:
if (parse_args_long_options(lgopts, option_index)) {
print_usage(prgname);
@ -1029,6 +1029,11 @@ parse_args(int32_t argc, char **argv)
}
}
if (f_present == 0) {
printf("Mandatory option \"-f\" not present\n");
return -1;
}
if (optind >= 0)
argv[optind-1] = prgname;
@ -1411,9 +1416,6 @@ main(int32_t argc, char **argv)
if (ret < 0)
rte_exit(EXIT_FAILURE, "Invalid parameters\n");
if (ep < 0)
rte_exit(EXIT_FAILURE, "need to choose either EP0 or EP1\n");
if ((unprotected_port_mask & enabled_port_mask) !=
unprotected_port_mask)
rte_exit(EXIT_FAILURE, "Invalid unprotected portmask 0x%x\n",
@ -1443,13 +1445,13 @@ main(int32_t argc, char **argv)
if (socket_ctx[socket_id].mbuf_pool)
continue;
sa_init(&socket_ctx[socket_id], socket_id, ep);
sa_init(&socket_ctx[socket_id], socket_id);
sp4_init(&socket_ctx[socket_id], socket_id, ep);
sp4_init(&socket_ctx[socket_id], socket_id);
sp6_init(&socket_ctx[socket_id], socket_id, ep);
sp6_init(&socket_ctx[socket_id], socket_id);
rt_init(&socket_ctx[socket_id], socket_id, ep);
rt_init(&socket_ctx[socket_id], socket_id);
pool_init(&socket_ctx[socket_id], socket_id, NB_MBUF);
}

View File

@ -90,6 +90,8 @@ struct ip_addr {
} ip;
};
#define MAX_KEY_SIZE 20
struct ipsec_sa {
uint32_t spi;
uint32_t cdev_id_qp;
@ -106,6 +108,10 @@ struct ipsec_sa {
#define TRANSPORT (1 << 2)
struct ip_addr src;
struct ip_addr dst;
uint8_t cipher_key[MAX_KEY_SIZE];
uint16_t cipher_key_len;
uint8_t auth_key[MAX_KEY_SIZE];
uint16_t auth_key_len;
struct rte_crypto_sym_xform *xforms;
} __rte_cache_aligned;
@ -183,15 +189,15 @@ outbound_sa_lookup(struct sa_ctx *sa_ctx, uint32_t sa_idx[],
struct ipsec_sa *sa[], uint16_t nb_pkts);
void
sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
sp4_init(struct socket_ctx *ctx, int32_t socket_id);
void
sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
sp6_init(struct socket_ctx *ctx, int32_t socket_id);
void
sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
sa_init(struct socket_ctx *ctx, int32_t socket_id);
void
rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep);
rt_init(struct socket_ctx *ctx, int32_t socket_id);
#endif /* __IPSEC_H__ */

View File

@ -0,0 +1,599 @@
/*-
* 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 <rte_common.h>
#include <rte_crypto.h>
#include <cmdline_parse_string.h>
#include <cmdline_parse_num.h>
#include <cmdline_parse_ipaddr.h>
#include <cmdline_socket.h>
#include <cmdline.h>
#include "ipsec.h"
#include "parser.h"
#define PARSE_DELIMITER " \f\n\r\t\v"
static int
parse_tokenize_string(char *string, char *tokens[], uint32_t *n_tokens)
{
uint32_t i;
if ((string == NULL) ||
(tokens == NULL) ||
(*n_tokens < 1))
return -EINVAL;
for (i = 0; i < *n_tokens; i++) {
tokens[i] = strtok_r(string, PARSE_DELIMITER, &string);
if (tokens[i] == NULL)
break;
}
if ((i == *n_tokens) &&
(NULL != strtok_r(string, PARSE_DELIMITER, &string)))
return -E2BIG;
*n_tokens = i;
return 0;
}
#define INADDRSZ 4
#define IN6ADDRSZ 16
/* int
* inet_pton4(src, dst)
* like inet_aton() but without all the hexadecimal and shorthand.
* return:
* 1 if `src' is a valid dotted quad, else 0.
* notice:
* does not touch `dst' unless it's returning 1.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton4(const char *src, unsigned char *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
unsigned char tmp[INADDRSZ], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
const char *pch;
pch = strchr(digits, ch);
if (pch != NULL) {
unsigned int new = *tp * 10 + (pch - digits);
if (new > 255)
return 0;
if (!saw_digit) {
if (++octets > 4)
return 0;
saw_digit = 1;
}
*tp = (unsigned char)new;
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return 0;
*++tp = 0;
saw_digit = 0;
} else
return 0;
}
if (octets < 4)
return 0;
memcpy(dst, tmp, INADDRSZ);
return 1;
}
/* int
* inet_pton6(src, dst)
* convert presentation level address to network order binary form.
* return:
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
* notice:
* (1) does not touch `dst' unless it's returning 1.
* (2) :: in a full address is silently ignored.
* credit:
* inspired by Mark Andrews.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton6(const char *src, unsigned char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
unsigned char tmp[IN6ADDRSZ], *tp = 0, *endp = 0, *colonp = 0;
const char *xdigits = 0, *curtok = 0;
int ch = 0, saw_xdigit = 0, count_xdigit = 0;
unsigned int val = 0;
unsigned dbloct_count = 0;
memset((tp = tmp), '\0', IN6ADDRSZ);
endp = tp + IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return 0;
curtok = src;
saw_xdigit = count_xdigit = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
pch = strchr((xdigits = xdigits_l), ch);
if (pch == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
if (count_xdigit >= 4)
return 0;
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return 0;
saw_xdigit = 1;
count_xdigit++;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return 0;
colonp = tp;
continue;
} else if (*src == '\0') {
return 0;
}
if (tp + sizeof(int16_t) > endp)
return 0;
*tp++ = (unsigned char) ((val >> 8) & 0xff);
*tp++ = (unsigned char) (val & 0xff);
saw_xdigit = 0;
count_xdigit = 0;
val = 0;
dbloct_count++;
continue;
}
if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
inet_pton4(curtok, tp) > 0) {
tp += INADDRSZ;
saw_xdigit = 0;
dbloct_count += 2;
break; /* '\0' was seen by inet_pton4(). */
}
return 0;
}
if (saw_xdigit) {
if (tp + sizeof(int16_t) > endp)
return 0;
*tp++ = (unsigned char) ((val >> 8) & 0xff);
*tp++ = (unsigned char) (val & 0xff);
dbloct_count++;
}
if (colonp != NULL) {
/* if we already have 8 double octets, having a colon
* means error */
if (dbloct_count == 8)
return 0;
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
for (i = 1; i <= n; i++) {
endp[-i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return 0;
memcpy(dst, tmp, IN6ADDRSZ);
return 1;
}
int
parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask)
{
char ip_str[256] = {0};
char *pch;
pch = strchr(token, '/');
if (pch != NULL) {
strncpy(ip_str, token, pch - token);
pch += 1;
if (is_str_num(pch) != 0)
return -EINVAL;
if (mask)
*mask = atoi(pch);
} else {
strncpy(ip_str, token, sizeof(ip_str));
if (mask)
*mask = 0;
}
if (strlen(ip_str) >= INET_ADDRSTRLEN)
return -EINVAL;
if (inet_pton4(ip_str, (unsigned char *)ipv4) != 1)
return -EINVAL;
return 0;
}
int
parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask)
{
char ip_str[256] = {0};
char *pch;
pch = strchr(token, '/');
if (pch != NULL) {
strncpy(ip_str, token, pch - token);
pch += 1;
if (is_str_num(pch) != 0)
return -EINVAL;
if (mask)
*mask = atoi(pch);
} else {
strncpy(ip_str, token, sizeof(ip_str));
if (mask)
*mask = 0;
}
if (strlen(ip_str) >= INET6_ADDRSTRLEN)
return -EINVAL;
if (inet_pton6(ip_str, (unsigned char *)ipv6) != 1)
return -EINVAL;
return 0;
}
int
parse_range(const char *token, uint16_t *low, uint16_t *high)
{
char ch;
char num_str[20];
uint32_t pos;
int range_low = -1;
int range_high = -1;
if (!low || !high)
return -1;
memset(num_str, 0, 20);
pos = 0;
while ((ch = *token++) != '\0') {
if (isdigit(ch)) {
if (pos >= 19)
return -1;
num_str[pos++] = ch;
} else if (ch == ':') {
if (range_low != -1)
return -1;
range_low = atoi(num_str);
memset(num_str, 0, 20);
pos = 0;
}
}
if (strlen(num_str) == 0)
return -1;
range_high = atoi(num_str);
*low = (uint16_t)range_low;
*high = (uint16_t)range_high;
return 0;
}
/** sp add parse */
struct cfg_sp_add_cfg_item {
cmdline_fixed_string_t sp_keyword;
cmdline_multi_string_t multi_string;
};
static void
cfg_sp_add_cfg_item_parsed(void *parsed_result,
__rte_unused struct cmdline *cl, void *data)
{
struct cfg_sp_add_cfg_item *params = parsed_result;
char *tokens[32];
uint32_t n_tokens = RTE_DIM(tokens);
struct parse_status *status = (struct parse_status *)data;
APP_CHECK((parse_tokenize_string(params->multi_string, tokens,
&n_tokens) == 0), status, "too many arguments");
if (status->status < 0)
return;
if (strcmp(tokens[0], "ipv4") == 0) {
parse_sp4_tokens(tokens, n_tokens, status);
if (status->status < 0)
return;
} else if (strcmp(tokens[0], "ipv6") == 0) {
parse_sp6_tokens(tokens, n_tokens, status);
if (status->status < 0)
return;
} else {
APP_CHECK(0, status, "unrecognizable input %s\n",
tokens[0]);
return;
}
}
static cmdline_parse_token_string_t cfg_sp_add_sp_str =
TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item,
sp_keyword, "sp");
static cmdline_parse_token_string_t cfg_sp_add_multi_str =
TOKEN_STRING_INITIALIZER(struct cfg_sp_add_cfg_item, multi_string,
TOKEN_STRING_MULTI);
cmdline_parse_inst_t cfg_sp_add_rule = {
.f = cfg_sp_add_cfg_item_parsed,
.data = NULL,
.help_str = "",
.tokens = {
(void *) &cfg_sp_add_sp_str,
(void *) &cfg_sp_add_multi_str,
NULL,
},
};
/* sa add parse */
struct cfg_sa_add_cfg_item {
cmdline_fixed_string_t sa_keyword;
cmdline_multi_string_t multi_string;
};
static void
cfg_sa_add_cfg_item_parsed(void *parsed_result,
__rte_unused struct cmdline *cl, void *data)
{
struct cfg_sa_add_cfg_item *params = parsed_result;
char *tokens[32];
uint32_t n_tokens = RTE_DIM(tokens);
struct parse_status *status = (struct parse_status *)data;
APP_CHECK(parse_tokenize_string(params->multi_string, tokens,
&n_tokens) == 0, status, "too many arguments\n");
parse_sa_tokens(tokens, n_tokens, status);
}
static cmdline_parse_token_string_t cfg_sa_add_sa_str =
TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item,
sa_keyword, "sa");
static cmdline_parse_token_string_t cfg_sa_add_multi_str =
TOKEN_STRING_INITIALIZER(struct cfg_sa_add_cfg_item, multi_string,
TOKEN_STRING_MULTI);
cmdline_parse_inst_t cfg_sa_add_rule = {
.f = cfg_sa_add_cfg_item_parsed,
.data = NULL,
.help_str = "",
.tokens = {
(void *) &cfg_sa_add_sa_str,
(void *) &cfg_sa_add_multi_str,
NULL,
},
};
/* rt add parse */
struct cfg_rt_add_cfg_item {
cmdline_fixed_string_t rt_keyword;
cmdline_multi_string_t multi_string;
};
static void
cfg_rt_add_cfg_item_parsed(void *parsed_result,
__rte_unused struct cmdline *cl, void *data)
{
struct cfg_rt_add_cfg_item *params = parsed_result;
char *tokens[32];
uint32_t n_tokens = RTE_DIM(tokens);
struct parse_status *status = (struct parse_status *)data;
APP_CHECK(parse_tokenize_string(
params->multi_string, tokens, &n_tokens) == 0,
status, "too many arguments\n");
if (status->status < 0)
return;
parse_rt_tokens(tokens, n_tokens, status);
}
static cmdline_parse_token_string_t cfg_rt_add_rt_str =
TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item,
rt_keyword, "rt");
static cmdline_parse_token_string_t cfg_rt_add_multi_str =
TOKEN_STRING_INITIALIZER(struct cfg_rt_add_cfg_item, multi_string,
TOKEN_STRING_MULTI);
cmdline_parse_inst_t cfg_rt_add_rule = {
.f = cfg_rt_add_cfg_item_parsed,
.data = NULL,
.help_str = "",
.tokens = {
(void *) &cfg_rt_add_rt_str,
(void *) &cfg_rt_add_multi_str,
NULL,
},
};
/** set of cfg items */
cmdline_parse_ctx_t ipsec_ctx[] = {
(cmdline_parse_inst_t *)&cfg_sp_add_rule,
(cmdline_parse_inst_t *)&cfg_sa_add_rule,
(cmdline_parse_inst_t *)&cfg_rt_add_rule,
NULL,
};
int
parse_cfg_file(const char *cfg_filename)
{
struct cmdline *cl = cmdline_stdin_new(ipsec_ctx, "");
FILE *f = fopen(cfg_filename, "r");
char str[1024] = {0}, *get_s = NULL;
uint32_t line_num = 0;
struct parse_status status = {0};
if (f == NULL) {
rte_panic("Error: invalid file descriptor %s\n",
cfg_filename);
goto error_exit;
}
if (cl == NULL) {
rte_panic("Error: cannot create cmdline instance\n");
goto error_exit;
}
cfg_sp_add_rule.data = &status;
cfg_sa_add_rule.data = &status;
cfg_rt_add_rule.data = &status;
do {
char oneline[1024];
get_s = fgets(oneline, 1024, f);
if (get_s) {
char *pos;
line_num++;
if (strlen(oneline) > 1022) {
rte_panic("%s:%u: error: the line "
"contains more characters the "
"parser can handle\n",
cfg_filename, line_num);
goto error_exit;
}
/* process comment char '#' */
if (oneline[0] == '#')
continue;
pos = strchr(oneline, '#');
if (pos != NULL)
*pos = '\0';
/* process line concatenator '\' */
pos = strchr(oneline, 92);
if (pos != NULL) {
if (pos != oneline+strlen(oneline) - 2) {
rte_panic("%s:%u: error: no "
"character should exist "
"after '\\' symbol\n",
cfg_filename, line_num);
goto error_exit;
}
*pos = '\0';
if (strlen(oneline) + strlen(str) > 1022) {
rte_panic("%s:%u: error: the "
"concatenated line "
"contains more characters "
"the parser can handle\n",
cfg_filename, line_num);
goto error_exit;
}
strncpy(str + strlen(str), oneline,
strlen(oneline));
continue;
}
/* copy the line to str and process */
if (strlen(oneline) + strlen(str) > 1022) {
rte_panic("%s:%u: error: the line "
"contains more characters the "
"parser can handle\n",
cfg_filename, line_num);
goto error_exit;
}
strncpy(str + strlen(str), oneline,
strlen(oneline));
str[strlen(str)] = '\n';
if (cmdline_parse(cl, str) < 0) {
rte_panic("%s:%u: error: parsing \"%s\" "
"failed\n", cfg_filename,
line_num, str);
goto error_exit;
}
if (status.status < 0) {
rte_panic("%s:%u: error: %s",
cfg_filename, line_num,
status.parse_msg);
goto error_exit;
}
memset(str, 0, 1024);
}
} while (get_s != NULL);
cmdline_stdin_exit(cl);
fclose(f);
return 0;
error_exit:
if (cl)
cmdline_stdin_exit(cl);
if (f)
fclose(f);
return -1;
}

View File

@ -0,0 +1,116 @@
/* 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 <sys/types.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#ifndef __PARSER_H
#define __PARSER_H
struct parse_status {
int status;
char parse_msg[256];
};
#define APP_CHECK(exp, status, fmt, ...) \
do { \
if (!(exp)) { \
sprintf(status->parse_msg, fmt "\n", \
## __VA_ARGS__); \
status->status = -1; \
} else \
status->status = 0; \
} while (0)
#define APP_CHECK_PRESENCE(val, str, status) \
APP_CHECK(val == 0, status, \
"item \"%s\" already present", str)
#define APP_CHECK_TOKEN_EQUAL(tokens, index, ref, status) \
APP_CHECK(strcmp(tokens[index], ref) == 0, status, \
"unrecognized input \"%s\": expect \"%s\"\n", \
tokens[index], ref)
static inline int
is_str_num(const char *str)
{
uint32_t i;
for (i = 0; i < strlen(str); i++)
if (!isdigit(str[i]))
return -1;
return 0;
}
#define APP_CHECK_TOKEN_IS_NUM(tokens, index, status) \
APP_CHECK(is_str_num(tokens[index]) == 0, status, \
"input \"%s\" is not valid number string", tokens[index])
#define INCREMENT_TOKEN_INDEX(index, max_num, status) \
do { \
APP_CHECK(index + 1 < max_num, status, "reaching the end of " \
"the token array"); \
index++; \
} while (0)
int
parse_ipv4_addr(const char *token, struct in_addr *ipv4, uint32_t *mask);
int
parse_ipv6_addr(const char *token, struct in6_addr *ipv6, uint32_t *mask);
int
parse_range(const char *token, uint16_t *low, uint16_t *high);
void
parse_sp4_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status);
void
parse_sp6_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status);
void
parse_sa_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status);
void
parse_rt_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status);
int
parse_cfg_file(const char *cfg_filename);
#endif

View File

@ -41,6 +41,7 @@
#include <rte_ip.h>
#include "ipsec.h"
#include "parser.h"
#define RT_IPV4_MAX_RULES 1024
#define RT_IPV6_MAX_RULES 1024
@ -57,135 +58,106 @@ struct ip6_route {
uint8_t if_out;
};
static struct ip4_route rt_ip4_ep0[] = {
/* Outbound */
/* Tunnels */
{ IPv4(172, 16, 2, 5), 32, 0 },
{ IPv4(172, 16, 2, 6), 32, 1 },
/* Transport */
{ IPv4(192, 168, 175, 0), 24, 0 },
{ IPv4(192, 168, 176, 0), 24, 1 },
/* Bypass */
{ IPv4(192, 168, 240, 0), 24, 0 },
{ IPv4(192, 168, 241, 0), 24, 1 },
struct ip4_route rt_ip4[RT_IPV4_MAX_RULES];
uint32_t nb_rt_ip4;
/* Inbound */
/* Tunnels */
{ IPv4(192, 168, 115, 0), 24, 2 },
{ IPv4(192, 168, 116, 0), 24, 3 },
{ IPv4(192, 168, 65, 0), 24, 2 },
{ IPv4(192, 168, 66, 0), 24, 3 },
/* Transport */
{ IPv4(192, 168, 185, 0), 24, 2 },
{ IPv4(192, 168, 186, 0), 24, 3 },
/* NULL */
{ IPv4(192, 168, 210, 0), 24, 2 },
{ IPv4(192, 168, 211, 0), 24, 3 },
/* Bypass */
{ IPv4(192, 168, 245, 0), 24, 2 },
{ IPv4(192, 168, 246, 0), 24, 3 },
};
static struct ip6_route rt_ip6_ep0[] = {
/* Outbound */
/* Tunnels */
{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 }, 116, 0 },
{ { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 }, 116, 1 },
/* Transport */
{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
/* Inbound */
/* Tunnels */
{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
{ { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
/* Transport */
{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
};
static struct ip4_route rt_ip4_ep1[] = {
/* Outbound */
/* Tunnels */
{ IPv4(172, 16, 1, 5), 32, 0 },
{ IPv4(172, 16, 1, 6), 32, 1 },
/* Transport */
{ IPv4(192, 168, 185, 0), 24, 0 },
{ IPv4(192, 168, 186, 0), 24, 1 },
/* Bypass */
{ IPv4(192, 168, 245, 0), 24, 0 },
{ IPv4(192, 168, 246, 0), 24, 1 },
/* Inbound */
/* Tunnels */
{ IPv4(192, 168, 105, 0), 24, 2 },
{ IPv4(192, 168, 106, 0), 24, 3 },
{ IPv4(192, 168, 55, 0), 24, 2 },
{ IPv4(192, 168, 56, 0), 24, 3 },
/* Transport */
{ IPv4(192, 168, 175, 0), 24, 2 },
{ IPv4(192, 168, 176, 0), 24, 3 },
/* NULL */
{ IPv4(192, 168, 200, 0), 24, 2 },
{ IPv4(192, 168, 201, 0), 24, 3 },
/* Bypass */
{ IPv4(192, 168, 240, 0), 24, 2 },
{ IPv4(192, 168, 241, 0), 24, 3 },
};
static struct ip6_route rt_ip6_ep1[] = {
/* Outbound */
/* Tunnels */
{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 }, 116, 0 },
{ { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 }, 116, 1 },
/* Transport */
{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 0 },
{ { 0xff, 0xff, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 1 },
/* Inbound */
/* Tunnels */
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa,
0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb,
0xbb, 0xbb, 0xbb, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55,
0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
{ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66,
0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
/* Transport */
{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 116, 2 },
{ { 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00 }, 116, 3 },
};
struct ip6_route rt_ip6[RT_IPV4_MAX_RULES];
uint32_t nb_rt_ip6;
void
rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
parse_rt_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status)
{
uint32_t ti;
uint32_t *n_rts = NULL;
struct ip4_route *route_ipv4 = NULL;
struct ip6_route *route_ipv6 = NULL;
if (strcmp(tokens[0], "ipv4") == 0) {
n_rts = &nb_rt_ip4;
route_ipv4 = &rt_ip4[*n_rts];
APP_CHECK(*n_rts <= RT_IPV4_MAX_RULES - 1, status,
"too many rt rules, abort insertion\n");
if (status->status < 0)
return;
} else if (strcmp(tokens[0], "ipv6") == 0) {
n_rts = &nb_rt_ip6;
route_ipv6 = &rt_ip6[*n_rts];
APP_CHECK(*n_rts <= RT_IPV6_MAX_RULES - 1, status,
"too many rt rules, abort insertion\n");
if (status->status < 0)
return;
} else {
APP_CHECK(0, status, "unrecognized input \"%s\"",
tokens[0]);
return;
}
for (ti = 1; ti < n_tokens; ti++) {
if (strcmp(tokens[ti], "dst") == 0) {
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
if (route_ipv4 != NULL) {
struct in_addr ip;
uint32_t depth = 0;
APP_CHECK(parse_ipv4_addr(tokens[ti],
&ip, &depth) == 0, status,
"unrecognized input \"%s\", "
"expect valid ipv4 addr",
tokens[ti]);
if (status->status < 0)
return;
route_ipv4->ip = rte_bswap32(
(uint32_t)ip.s_addr);
route_ipv4->depth = (uint8_t)depth;
} else {
struct in6_addr ip;
uint32_t depth;
APP_CHECK(parse_ipv6_addr(tokens[ti],
&ip, &depth) == 0, status,
"unrecognized input \"%s\", "
"expect valid ipv6 address",
tokens[ti]);
if (status->status < 0)
return;
memcpy(route_ipv6->ip, ip.s6_addr, 16);
route_ipv6->depth = (uint8_t)depth;
}
}
if (strcmp(tokens[ti], "port") == 0) {
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
if (status->status < 0)
return;
if (route_ipv4 != NULL)
route_ipv4->if_out = atoi(tokens[ti]);
else
route_ipv6->if_out = atoi(tokens[ti]);
}
}
*n_rts = *n_rts + 1;
}
void
rt_init(struct socket_ctx *ctx, int32_t socket_id)
{
char name[PATH_MAX];
uint32_t i;
int32_t ret;
struct rte_lpm *lpm;
struct rte_lpm6 *lpm6;
struct ip4_route *rt;
struct ip6_route *rt6;
char a, b, c, d;
uint32_t nb_routes, nb_routes6;
struct rte_lpm_config conf = { 0 };
struct rte_lpm6_config conf6 = { 0 };
@ -200,23 +172,12 @@ rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
rte_exit(EXIT_FAILURE, "IPv6 Routing Table for socket %u "
"already initialized\n", socket_id);
if (nb_rt_ip4 == 0 && nb_rt_ip6 == 0)
RTE_LOG(WARNING, IPSEC, "No Routing rule specified\n");
printf("Creating IPv4 Routing Table (RT) context with %u max routes\n",
RT_IPV4_MAX_RULES);
if (ep == 0) {
rt = rt_ip4_ep0;
nb_routes = RTE_DIM(rt_ip4_ep0);
rt6 = rt_ip6_ep0;
nb_routes6 = RTE_DIM(rt_ip6_ep0);
} else if (ep == 1) {
rt = rt_ip4_ep1;
nb_routes = RTE_DIM(rt_ip4_ep1);
rt6 = rt_ip6_ep1;
nb_routes6 = RTE_DIM(rt_ip6_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_ip4", socket_id);
conf.max_rules = RT_IPV4_MAX_RULES;
@ -227,15 +188,17 @@ rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
"on socket %d\n", name, 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);
for (i = 0; i < nb_rt_ip4; i++) {
ret = rte_lpm_add(lpm, rt_ip4[i].ip, rt_ip4[i].depth,
rt_ip4[i].if_out);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
"LPM table on socket %d\n", i, name, socket_id);
uint32_t_to_char(rt[i].ip, &a, &b, &c, &d);
uint32_t_to_char(rt_ip4[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);
a, b, c, d, rt_ip4[i].depth,
rt_ip4[i].if_out);
}
snprintf(name, sizeof(name), "%s_%u", "rt_ip6", socket_id);
@ -247,24 +210,24 @@ rt_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
"on socket %d\n", name, socket_id);
/* populate the LPM table */
for (i = 0; i < nb_routes6; i++) {
ret = rte_lpm6_add(lpm6, rt6[i].ip, rt6[i].depth,
rt6[i].if_out);
for (i = 0; i < nb_rt_ip6; i++) {
ret = rte_lpm6_add(lpm6, rt_ip6[i].ip, rt_ip6[i].depth,
rt_ip6[i].if_out);
if (ret < 0)
rte_exit(EXIT_FAILURE, "Fail to add entry num %u to %s "
"LPM table on socket %d\n", i, name, socket_id);
printf("LPM6: Adding route "
" %hx:%hx:%hx:%hx:%hx:%hx:%hx:%hx/%hhx (%hhx)\n",
(uint16_t)((rt6[i].ip[0] << 8) | rt6[i].ip[1]),
(uint16_t)((rt6[i].ip[2] << 8) | rt6[i].ip[3]),
(uint16_t)((rt6[i].ip[4] << 8) | rt6[i].ip[5]),
(uint16_t)((rt6[i].ip[6] << 8) | rt6[i].ip[7]),
(uint16_t)((rt6[i].ip[8] << 8) | rt6[i].ip[9]),
(uint16_t)((rt6[i].ip[10] << 8) | rt6[i].ip[11]),
(uint16_t)((rt6[i].ip[12] << 8) | rt6[i].ip[13]),
(uint16_t)((rt6[i].ip[14] << 8) | rt6[i].ip[15]),
rt6[i].depth, rt6[i].if_out);
(uint16_t)((rt_ip6[i].ip[0] << 8) | rt_ip6[i].ip[1]),
(uint16_t)((rt_ip6[i].ip[2] << 8) | rt_ip6[i].ip[3]),
(uint16_t)((rt_ip6[i].ip[4] << 8) | rt_ip6[i].ip[5]),
(uint16_t)((rt_ip6[i].ip[6] << 8) | rt_ip6[i].ip[7]),
(uint16_t)((rt_ip6[i].ip[8] << 8) | rt_ip6[i].ip[9]),
(uint16_t)((rt_ip6[i].ip[10] << 8) | rt_ip6[i].ip[11]),
(uint16_t)((rt_ip6[i].ip[12] << 8) | rt_ip6[i].ip[13]),
(uint16_t)((rt_ip6[i].ip[14] << 8) | rt_ip6[i].ip[15]),
rt_ip6[i].depth, rt_ip6[i].if_out);
}
ctx->rt_ip4 = (struct rt_ctx *)lpm;

View File

@ -48,243 +48,457 @@
#include "ipsec.h"
#include "esp.h"
#include "parser.h"
/* SAs Outbound */
const struct ipsec_sa sa_out[] = {
{
.spi = 5,
.src.ip.ip4 = IPv4(172, 16, 1, 5),
.dst.ip.ip4 = IPv4(172, 16, 2, 5),
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP4_TUNNEL
},
{
.spi = 6,
.src.ip.ip4 = IPv4(172, 16, 1, 6),
.dst.ip.ip4 = IPv4(172, 16, 2, 6),
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP4_TUNNEL
},
{
.spi = 10,
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = TRANSPORT
},
{
.spi = 11,
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = TRANSPORT
},
{
.spi = 15,
.src.ip.ip4 = IPv4(172, 16, 1, 5),
.dst.ip.ip4 = IPv4(172, 16, 2, 5),
.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
.auth_algo = RTE_CRYPTO_AUTH_NULL,
.digest_len = 0,
.iv_len = 0,
.block_size = 4,
.flags = IP4_TUNNEL
},
{
.spi = 16,
.src.ip.ip4 = IPv4(172, 16, 1, 6),
.dst.ip.ip4 = IPv4(172, 16, 2, 6),
.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
.auth_algo = RTE_CRYPTO_AUTH_NULL,
.digest_len = 0,
.iv_len = 0,
.block_size = 4,
.flags = IP4_TUNNEL
},
{
.spi = 25,
.src.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
.dst.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP6_TUNNEL
},
{
.spi = 26,
.src.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
.dst.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP6_TUNNEL
},
struct supported_cipher_algo {
const char *keyword;
enum rte_crypto_cipher_algorithm algo;
uint16_t iv_len;
uint16_t block_size;
uint16_t key_len;
};
/* SAs Inbound */
const struct ipsec_sa sa_in[] = {
{
.spi = 105,
.src.ip.ip4 = IPv4(172, 16, 2, 5),
.dst.ip.ip4 = IPv4(172, 16, 1, 5),
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP4_TUNNEL
},
{
.spi = 106,
.src.ip.ip4 = IPv4(172, 16, 2, 6),
.dst.ip.ip4 = IPv4(172, 16, 1, 6),
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP4_TUNNEL
},
{
.spi = 110,
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = TRANSPORT
},
{
.spi = 111,
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = TRANSPORT
},
{
.spi = 115,
.src.ip.ip4 = IPv4(172, 16, 2, 5),
.dst.ip.ip4 = IPv4(172, 16, 1, 5),
.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
.auth_algo = RTE_CRYPTO_AUTH_NULL,
.digest_len = 0,
.iv_len = 0,
.block_size = 4,
.flags = IP4_TUNNEL
},
{
.spi = 116,
.src.ip.ip4 = IPv4(172, 16, 2, 6),
.dst.ip.ip4 = IPv4(172, 16, 1, 6),
.cipher_algo = RTE_CRYPTO_CIPHER_NULL,
.auth_algo = RTE_CRYPTO_AUTH_NULL,
.digest_len = 0,
.iv_len = 0,
.block_size = 4,
.flags = IP4_TUNNEL
},
{
.spi = 125,
.src.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x55, 0x55 },
.dst.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x55, 0x55 },
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP6_TUNNEL
},
{
.spi = 126,
.src.ip.ip6.ip6_b = { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x66, 0x66 },
.dst.ip.ip6.ip6_b = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x66, 0x66 },
.cipher_algo = RTE_CRYPTO_CIPHER_AES_CBC,
.auth_algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.iv_len = 16,
.block_size = 16,
.flags = IP6_TUNNEL
},
struct supported_auth_algo {
const char *keyword;
enum rte_crypto_auth_algorithm algo;
uint16_t digest_len;
uint16_t key_len;
};
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 supported_cipher_algo cipher_algos[] = {
{
.keyword = "null",
.algo = RTE_CRYPTO_CIPHER_NULL,
.iv_len = 0,
.block_size = 4,
.key_len = 0
},
{
.keyword = "aes-128-cbc",
.algo = RTE_CRYPTO_CIPHER_AES_CBC,
.iv_len = 16,
.block_size = 16,
.key_len = 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 } }
const struct supported_auth_algo auth_algos[] = {
{
.keyword = "null",
.algo = RTE_CRYPTO_AUTH_NULL,
.digest_len = 0,
.key_len = 0
},
{
.keyword = "sha1-hmac",
.algo = RTE_CRYPTO_AUTH_SHA1_HMAC,
.digest_len = 12,
.key_len = 20
}
};
static uint8_t auth_key[256] = "twentybytes hash key";
struct ipsec_sa sa_out[IPSEC_SA_MAX_ENTRIES];
uint32_t nb_sa_out;
/* 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 }
}
};
struct ipsec_sa sa_in[IPSEC_SA_MAX_ENTRIES];
uint32_t nb_sa_in;
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 }
}
};
static const struct supported_cipher_algo *
find_match_cipher_algo(const char *cipher_keyword)
{
size_t i;
/* AES CBC xform */
const struct rte_crypto_sym_xform null_cipher_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_CIPHER,
{.cipher = { .algo = RTE_CRYPTO_CIPHER_NULL }
}
};
for (i = 0; i < RTE_DIM(cipher_algos); i++) {
const struct supported_cipher_algo *algo =
&cipher_algos[i];
const struct rte_crypto_sym_xform null_auth_xf = {
NULL,
RTE_CRYPTO_SYM_XFORM_AUTH,
{.auth = { .algo = RTE_CRYPTO_AUTH_NULL }
if (strcmp(cipher_keyword, algo->keyword) == 0)
return algo;
}
};
return NULL;
}
static const struct supported_auth_algo *
find_match_auth_algo(const char *auth_keyword)
{
size_t i;
for (i = 0; i < RTE_DIM(auth_algos); i++) {
const struct supported_auth_algo *algo =
&auth_algos[i];
if (strcmp(auth_keyword, algo->keyword) == 0)
return algo;
}
return NULL;
}
/** parse_key_string
* parse x:x:x:x.... hex number key string into uint8_t *key
* return:
* > 0: number of bytes parsed
* 0: failed
*/
static uint32_t
parse_key_string(const char *key_str, uint8_t *key)
{
const char *pt_start = key_str, *pt_end = key_str;
char sub_str[3];
uint32_t nb_bytes = 0;
while (pt_end != NULL) {
pt_end = strchr(pt_start, ':');
if (pt_end == NULL)
strncpy(sub_str, pt_start, strlen(pt_start));
else {
if (pt_end - pt_start > 2)
return 0;
strncpy(sub_str, pt_start, pt_end - pt_start);
pt_start = pt_end + 1;
}
key[nb_bytes++] = strtol(sub_str, NULL, 16);
}
return nb_bytes;
}
void
parse_sa_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status)
{
struct ipsec_sa *rule = NULL;
uint32_t ti; /*token index*/
uint32_t *ri /*rule index*/;
uint32_t cipher_algo_p = 0;
uint32_t auth_algo_p = 0;
uint32_t src_p = 0;
uint32_t dst_p = 0;
uint32_t mode_p = 0;
if (strcmp(tokens[0], "in") == 0) {
ri = &nb_sa_in;
APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
"too many sa rules, abort insertion\n");
if (status->status < 0)
return;
rule = &sa_in[*ri];
} else {
ri = &nb_sa_out;
APP_CHECK(*ri <= IPSEC_SA_MAX_ENTRIES - 1, status,
"too many sa rules, abort insertion\n");
if (status->status < 0)
return;
rule = &sa_out[*ri];
}
/* spi number */
APP_CHECK_TOKEN_IS_NUM(tokens, 1, status);
if (status->status < 0)
return;
rule->spi = atoi(tokens[1]);
for (ti = 2; ti < n_tokens; ti++) {
if (strcmp(tokens[ti], "mode") == 0) {
APP_CHECK_PRESENCE(mode_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
if (strcmp(tokens[ti], "ipv4-tunnel") == 0)
rule->flags = IP4_TUNNEL;
else if (strcmp(tokens[ti], "ipv6-tunnel") == 0)
rule->flags = IP6_TUNNEL;
else if (strcmp(tokens[ti], "transport") == 0)
rule->flags = TRANSPORT;
else {
APP_CHECK(0, status, "unrecognized "
"input \"%s\"", tokens[ti]);
return;
}
mode_p = 1;
continue;
}
if (strcmp(tokens[ti], "cipher_algo") == 0) {
const struct supported_cipher_algo *algo;
uint32_t key_len;
APP_CHECK_PRESENCE(cipher_algo_p, tokens[ti],
status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
algo = find_match_cipher_algo(tokens[ti]);
APP_CHECK(algo != NULL, status, "unrecognized "
"input \"%s\"", tokens[ti]);
rule->cipher_algo = algo->algo;
rule->block_size = algo->block_size;
rule->iv_len = algo->iv_len;
rule->cipher_key_len = algo->key_len;
/* for NULL algorithm, no cipher key should
* exist */
if (rule->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
cipher_algo_p = 1;
continue;
}
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(strcmp(tokens[ti], "cipher_key") == 0,
status, "unrecognized input \"%s\", "
"expect \"cipher_key\"", tokens[ti]);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
key_len = parse_key_string(tokens[ti],
rule->cipher_key);
APP_CHECK(key_len == rule->cipher_key_len, status,
"unrecognized input \"%s\"", tokens[ti]);
if (status->status < 0)
return;
cipher_algo_p = 1;
continue;
}
if (strcmp(tokens[ti], "auth_algo") == 0) {
const struct supported_auth_algo *algo;
uint32_t key_len;
APP_CHECK_PRESENCE(auth_algo_p, tokens[ti],
status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
algo = find_match_auth_algo(tokens[ti]);
APP_CHECK(algo != NULL, status, "unrecognized "
"input \"%s\"", tokens[ti]);
rule->auth_algo = algo->algo;
rule->auth_key_len = algo->key_len;
rule->digest_len = algo->digest_len;
/* for NULL algorithm, no auth key should exist */
if (rule->auth_algo == RTE_CRYPTO_AUTH_NULL) {
auth_algo_p = 1;
continue;
}
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(strcmp(tokens[ti], "auth_key") == 0,
status, "unrecognized input \"%s\", "
"expect \"auth_key\"", tokens[ti]);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
key_len = parse_key_string(tokens[ti],
rule->auth_key);
APP_CHECK(key_len == rule->auth_key_len, status,
"unrecognized input \"%s\"", tokens[ti]);
if (status->status < 0)
return;
auth_algo_p = 1;
continue;
}
if (strcmp(tokens[ti], "src") == 0) {
APP_CHECK_PRESENCE(src_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
if (rule->flags == IP4_TUNNEL) {
struct in_addr ip;
APP_CHECK(parse_ipv4_addr(tokens[ti],
&ip, NULL) == 0, status,
"unrecognized input \"%s\", "
"expect valid ipv4 addr",
tokens[ti]);
if (status->status < 0)
return;
rule->src.ip.ip4 = rte_bswap32(
(uint32_t)ip.s_addr);
} else if (rule->flags == IP6_TUNNEL) {
struct in6_addr ip;
APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
NULL) == 0, status,
"unrecognized input \"%s\", "
"expect valid ipv6 addr",
tokens[ti]);
if (status->status < 0)
return;
memcpy(rule->src.ip.ip6.ip6_b,
ip.s6_addr, 16);
} else if (rule->flags == TRANSPORT) {
APP_CHECK(0, status, "unrecognized input "
"\"%s\"", tokens[ti]);
return;
}
src_p = 1;
continue;
}
if (strcmp(tokens[ti], "dst") == 0) {
APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
if (rule->flags == IP4_TUNNEL) {
struct in_addr ip;
APP_CHECK(parse_ipv4_addr(tokens[ti],
&ip, NULL) == 0, status,
"unrecognized input \"%s\", "
"expect valid ipv4 addr",
tokens[ti]);
if (status->status < 0)
return;
rule->dst.ip.ip4 = rte_bswap32(
(uint32_t)ip.s_addr);
} else if (rule->flags == IP6_TUNNEL) {
struct in6_addr ip;
APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
NULL) == 0, status,
"unrecognized input \"%s\", "
"expect valid ipv6 addr",
tokens[ti]);
if (status->status < 0)
return;
memcpy(rule->dst.ip.ip6.ip6_b, ip.s6_addr, 16);
} else if (rule->flags == TRANSPORT) {
APP_CHECK(0, status, "unrecognized "
"input \"%s\"", tokens[ti]);
return;
}
dst_p = 1;
continue;
}
/* unrecognizeable input */
APP_CHECK(0, status, "unrecognized input \"%s\"",
tokens[ti]);
return;
}
APP_CHECK(cipher_algo_p == 1, status, "missing cipher options");
if (status->status < 0)
return;
APP_CHECK(auth_algo_p == 1, status, "missing auth options");
if (status->status < 0)
return;
APP_CHECK(mode_p == 1, status, "missing mode option");
if (status->status < 0)
return;
*ri = *ri + 1;
}
static inline void
print_one_sa_rule(const struct ipsec_sa *sa, int inbound)
{
uint32_t i;
uint8_t a, b, c, d;
printf("\tspi_%s(%3u):", inbound?"in":"out", sa->spi);
for (i = 0; i < RTE_DIM(cipher_algos); i++) {
if (cipher_algos[i].algo == sa->cipher_algo) {
printf("%s ", cipher_algos[i].keyword);
break;
}
}
for (i = 0; i < RTE_DIM(auth_algos); i++) {
if (auth_algos[i].algo == sa->auth_algo) {
printf("%s ", auth_algos[i].keyword);
break;
}
}
printf("mode:");
switch (sa->flags) {
case IP4_TUNNEL:
printf("IP4Tunnel ");
uint32_t_to_char(sa->src.ip.ip4, &a, &b, &c, &d);
printf("%hhu.%hhu.%hhu.%hhu ", d, c, b, a);
uint32_t_to_char(sa->dst.ip.ip4, &a, &b, &c, &d);
printf("%hhu.%hhu.%hhu.%hhu", d, c, b, a);
break;
case IP6_TUNNEL:
printf("IP6Tunnel ");
for (i = 0; i < 16; i++) {
if (i % 2 && i != 15)
printf("%.2x:", sa->src.ip.ip6.ip6_b[i]);
else
printf("%.2x", sa->src.ip.ip6.ip6_b[i]);
}
printf(" ");
for (i = 0; i < 16; i++) {
if (i % 2 && i != 15)
printf("%.2x:", sa->dst.ip.ip6.ip6_b[i]);
else
printf("%.2x", sa->dst.ip.ip6.ip6_b[i]);
}
break;
case TRANSPORT:
printf("Transport");
break;
}
printf("\n");
}
struct sa_ctx {
struct ipsec_sa sa[IPSEC_SA_MAX_ENTRIES];
@ -347,25 +561,53 @@ sa_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
}
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;
}
sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
sa_ctx->xf[idx].b.cipher.algo = sa->cipher_algo;
sa_ctx->xf[idx].b.cipher.key.data = sa->cipher_key;
sa_ctx->xf[idx].b.cipher.key.length =
sa->cipher_key_len;
sa_ctx->xf[idx].b.cipher.op =
RTE_CRYPTO_CIPHER_OP_DECRYPT;
sa_ctx->xf[idx].b.next = NULL;
sa_ctx->xf[idx].a.type = RTE_CRYPTO_SYM_XFORM_AUTH;
sa_ctx->xf[idx].a.auth.algo = sa->auth_algo;
sa_ctx->xf[idx].a.auth.add_auth_data_length = 0;
sa_ctx->xf[idx].a.auth.key.data = sa->auth_key;
sa_ctx->xf[idx].a.auth.key.length =
sa->auth_key_len;
sa_ctx->xf[idx].a.auth.digest_length =
sa->digest_len;
sa_ctx->xf[idx].a.auth.op =
RTE_CRYPTO_AUTH_OP_VERIFY;
} 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.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
sa_ctx->xf[idx].a.cipher.algo = sa->cipher_algo;
sa_ctx->xf[idx].a.cipher.key.data = sa->cipher_key;
sa_ctx->xf[idx].a.cipher.key.length =
sa->cipher_key_len;
sa_ctx->xf[idx].a.cipher.op =
RTE_CRYPTO_CIPHER_OP_ENCRYPT;
sa_ctx->xf[idx].a.next = NULL;
sa_ctx->xf[idx].b.type = RTE_CRYPTO_SYM_XFORM_AUTH;
sa_ctx->xf[idx].b.auth.algo = sa->auth_algo;
sa_ctx->xf[idx].b.auth.add_auth_data_length = 0;
sa_ctx->xf[idx].b.auth.key.data = sa->auth_key;
sa_ctx->xf[idx].b.auth.key.length =
sa->auth_key_len;
sa_ctx->xf[idx].b.auth.digest_length =
sa->digest_len;
sa_ctx->xf[idx].b.auth.op =
RTE_CRYPTO_AUTH_OP_GENERATE;
}
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;
print_one_sa_rule(sa, inbound);
}
return 0;
@ -386,10 +628,8 @@ sa_in_add_rules(struct sa_ctx *sa_ctx, const struct ipsec_sa entries[],
}
void
sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
sa_init(struct socket_ctx *ctx, int32_t socket_id)
{
const struct ipsec_sa *sa_out_entries, *sa_in_entries;
uint32_t nb_out_entries, nb_in_entries;
const char *name;
if (ctx == NULL)
@ -403,35 +643,30 @@ sa_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
rte_exit(EXIT_FAILURE, "Outbound SA DB for socket %u already "
"initialized\n", socket_id);
if (ep == 0) {
sa_out_entries = sa_out;
nb_out_entries = RTE_DIM(sa_out);
sa_in_entries = sa_in;
nb_in_entries = RTE_DIM(sa_in);
} else if (ep == 1) {
sa_out_entries = sa_in;
nb_out_entries = RTE_DIM(sa_in);
sa_in_entries = sa_out;
nb_in_entries = RTE_DIM(sa_out);
if (nb_sa_in > 0) {
name = "sa_in";
ctx->sa_in = sa_create(name, socket_id);
if (ctx->sa_in == 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_in, sa_in, nb_sa_in);
} else
rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
"Only 0 or 1 supported.\n", ep);
RTE_LOG(WARNING, IPSEC, "No SA Inbound rule specified\n");
name = "sa_in";
ctx->sa_in = sa_create(name, socket_id);
if (ctx->sa_in == NULL)
rte_exit(EXIT_FAILURE, "Error [%d] creating SA context %s "
"in socket %d\n", rte_errno, name, socket_id);
if (nb_sa_out > 0) {
name = "sa_out";
ctx->sa_out = sa_create(name, socket_id);
if (ctx->sa_out == NULL)
rte_exit(EXIT_FAILURE, "Error [%d] creating SA "
"context %s in socket %d\n", rte_errno,
name, socket_id);
name = "sa_out";
ctx->sa_out = sa_create(name, socket_id);
if (ctx->sa_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_in, sa_in_entries, nb_in_entries);
sa_out_add_rules(ctx->sa_out, sa_out_entries, nb_out_entries);
sa_out_add_rules(ctx->sa_out, sa_out, nb_sa_out);
} else
RTE_LOG(WARNING, IPSEC, "No SA Outbound rule "
"specified\n");
}
int

View File

@ -42,8 +42,9 @@
#include <rte_ip.h>
#include "ipsec.h"
#include "parser.h"
#define MAX_ACL_RULE_NUM 1000
#define MAX_ACL_RULE_NUM 1024
/*
* Rule and trace formats definitions.
@ -113,211 +114,306 @@ struct rte_acl_field_def ip4_defs[NUM_FIELDS_IPV4] = {
RTE_ACL_RULE_DEF(acl4_rules, RTE_DIM(ip4_defs));
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, 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 = 1},
/* 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(10), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 175, 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(11), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 176, 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(15), .category_mask = 1, .priority = 1},
/* 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 = PROTECT(16), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 201, 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(25), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 55, 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(26), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 56, 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 = 1},
/* 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,}
},
{
.data = {.userdata = BYPASS, .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 241, 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,}
}
};
struct acl4_rules acl4_rules_out[MAX_ACL_RULE_NUM];
uint32_t nb_acl4_rules_out;
const struct acl4_rules acl4_rules_in[] = {
{
.data = {.userdata = PROTECT(105), .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(106), .category_mask = 1, .priority = 1},
/* 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(110), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 185, 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(111), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 186, 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(115), .category_mask = 1, .priority = 1},
/* 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 = PROTECT(116), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 211, 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(125), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 65, 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(126), .category_mask = 1, .priority = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 66, 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 = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 245, 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 = 1},
/* destination IPv4 */
.field[2] = {.value.u32 = IPv4(192, 168, 246, 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,}
struct acl4_rules acl4_rules_in[MAX_ACL_RULE_NUM];
uint32_t nb_acl4_rules_in;
void
parse_sp4_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status)
{
struct acl4_rules *rule_ipv4 = NULL;
uint32_t *ri = NULL; /* rule index */
uint32_t ti = 0; /* token index */
uint32_t esp_p = 0;
uint32_t protect_p = 0;
uint32_t bypass_p = 0;
uint32_t discard_p = 0;
uint32_t pri_p = 0;
uint32_t src_p = 0;
uint32_t dst_p = 0;
uint32_t proto_p = 0;
uint32_t sport_p = 0;
uint32_t dport_p = 0;
if (strcmp(tokens[1], "in") == 0) {
ri = &nb_acl4_rules_in;
APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
"too many sp rules, abort insertion\n");
if (status->status < 0)
return;
rule_ipv4 = &acl4_rules_in[*ri];
} else if (strcmp(tokens[1], "out") == 0) {
ri = &nb_acl4_rules_out;
APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status,
"too many sp rules, abort insertion\n");
if (status->status < 0)
return;
rule_ipv4 = &acl4_rules_out[*ri];
} else {
APP_CHECK(0, status, "unrecognized input \"%s\", expect"
" \"in\" or \"out\"\n", tokens[ti]);
return;
}
};
rule_ipv4->data.category_mask = 1;
for (ti = 2; ti < n_tokens; ti++) {
if (strcmp(tokens[ti], "esp") == 0) {
/* currently do nothing */
APP_CHECK_PRESENCE(esp_p, tokens[ti], status);
if (status->status < 0)
return;
esp_p = 1;
continue;
}
if (strcmp(tokens[ti], "protect") == 0) {
APP_CHECK_PRESENCE(protect_p, tokens[ti], status);
if (status->status < 0)
return;
APP_CHECK(bypass_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"bypass");
if (status->status < 0)
return;
APP_CHECK(discard_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"discard");
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
if (status->status < 0)
return;
rule_ipv4->data.userdata =
PROTECT(atoi(tokens[ti]));
protect_p = 1;
continue;
}
if (strcmp(tokens[ti], "bypass") == 0) {
APP_CHECK_PRESENCE(bypass_p, tokens[ti], status);
if (status->status < 0)
return;
APP_CHECK(protect_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"protect");
if (status->status < 0)
return;
APP_CHECK(discard_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"discard");
if (status->status < 0)
return;
rule_ipv4->data.userdata = BYPASS;
bypass_p = 1;
continue;
}
if (strcmp(tokens[ti], "discard") == 0) {
APP_CHECK_PRESENCE(discard_p, tokens[ti], status);
if (status->status < 0)
return;
APP_CHECK(protect_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"protect");
if (status->status < 0)
return;
APP_CHECK(bypass_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"discard");
if (status->status < 0)
return;
rule_ipv4->data.userdata = DISCARD;
discard_p = 1;
continue;
}
if (strcmp(tokens[ti], "pri") == 0) {
APP_CHECK_PRESENCE(pri_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
if (status->status < 0)
return;
rule_ipv4->data.priority = atoi(tokens[ti]);
pri_p = 1;
continue;
}
if (strcmp(tokens[ti], "src") == 0) {
struct in_addr ip;
uint32_t depth;
APP_CHECK_PRESENCE(src_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_ipv4_addr(tokens[ti], &ip,
&depth) == 0, status, "unrecognized "
"input \"%s\", expect valid ipv4 addr",
tokens[ti]);
if (status->status < 0)
return;
rule_ipv4->field[1].value.u32 =
rte_bswap32(ip.s_addr);
rule_ipv4->field[1].mask_range.u32 =
depth;
src_p = 1;
continue;
}
if (strcmp(tokens[ti], "dst") == 0) {
struct in_addr ip;
uint32_t depth;
APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_ipv4_addr(tokens[ti], &ip,
&depth) == 0, status, "unrecognized "
"input \"%s\", expect valid ipv4 addr",
tokens[ti]);
if (status->status < 0)
return;
rule_ipv4->field[2].value.u32 =
rte_bswap32(ip.s_addr);
rule_ipv4->field[2].mask_range.u32 =
depth;
dst_p = 1;
continue;
}
if (strcmp(tokens[ti], "proto") == 0) {
uint16_t low, high;
APP_CHECK_PRESENCE(proto_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_range(tokens[ti], &low, &high)
== 0, status, "unrecognized input \"%s\""
", expect \"from:to\"", tokens[ti]);
if (status->status < 0)
return;
APP_CHECK(low <= 0xff, status, "proto low "
"over-limit");
if (status->status < 0)
return;
APP_CHECK(high <= 0xff, status, "proto high "
"over-limit");
if (status->status < 0)
return;
rule_ipv4->field[0].value.u8 = (uint8_t)low;
rule_ipv4->field[0].mask_range.u8 = (uint8_t)high;
proto_p = 1;
continue;
}
if (strcmp(tokens[ti], "sport") == 0) {
uint16_t port_low, port_high;
APP_CHECK_PRESENCE(sport_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_range(tokens[ti], &port_low,
&port_high) == 0, status, "unrecognized "
"input \"%s\", expect \"port_from:"
"port_to\"", tokens[ti]);
if (status->status < 0)
return;
rule_ipv4->field[3].value.u16 = port_low;
rule_ipv4->field[3].mask_range.u16 = port_high;
sport_p = 1;
continue;
}
if (strcmp(tokens[ti], "dport") == 0) {
uint16_t port_low, port_high;
APP_CHECK_PRESENCE(dport_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_range(tokens[ti], &port_low,
&port_high) == 0, status, "unrecognized "
"input \"%s\", expect \"port_from:"
"port_to\"", tokens[ti]);
if (status->status < 0)
return;
rule_ipv4->field[4].value.u16 = port_low;
rule_ipv4->field[4].mask_range.u16 = port_high;
dport_p = 1;
continue;
}
/* unrecognizeable input */
APP_CHECK(0, status, "unrecognized input \"%s\"",
tokens[ti]);
return;
}
/* check if argument(s) are missing */
APP_CHECK(esp_p == 1, status, "missing argument \"esp\"");
if (status->status < 0)
return;
APP_CHECK(protect_p | bypass_p | discard_p, status, "missing "
"argument \"protect\", \"bypass\", or \"discard\"");
if (status->status < 0)
return;
*ri = *ri + 1;
}
static void
print_one_ip4_rule(const struct acl4_rules *rule, int32_t extra)
@ -406,11 +502,9 @@ acl4_init(const char *name, int32_t socketid, const struct acl4_rules *rules,
}
void
sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
sp4_init(struct socket_ctx *ctx, int32_t socket_id)
{
const char *name;
const struct acl4_rules *rules_out, *rules_in;
uint32_t nb_out_rules, nb_in_rules;
if (ctx == NULL)
rte_exit(EXIT_FAILURE, "NULL context.\n");
@ -423,25 +517,19 @@ sp4_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
rte_exit(EXIT_FAILURE, "Outbound SP DB for socket %u already "
"initialized\n", socket_id);
if (ep == 0) {
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 if (ep == 1) {
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);
if (nb_acl4_rules_in > 0) {
name = "sp_ip4_in";
ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name,
socket_id, acl4_rules_in, nb_acl4_rules_in);
} else
rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
"Only 0 or 1 supported.\n", ep);
RTE_LOG(WARNING, IPSEC, "No IPv4 SP Inbound rule "
"specified\n");
name = "sp_ip4_in";
ctx->sp_ip4_in = (struct sp_ctx *)acl4_init(name, socket_id,
rules_in, nb_in_rules);
name = "sp_ip4_out";
ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name, socket_id,
rules_out, nb_out_rules);
if (nb_acl4_rules_out > 0) {
name = "sp_ip4_out";
ctx->sp_ip4_out = (struct sp_ctx *)acl4_init(name,
socket_id, acl4_rules_out, nb_acl4_rules_out);
} else
RTE_LOG(WARNING, IPSEC, "No IPv4 SP Outbound rule "
"specified\n");
}

View File

@ -42,8 +42,9 @@
#include <rte_ip.h>
#include "ipsec.h"
#include "parser.h"
#define MAX_ACL_RULE_NUM 1000
#define MAX_ACL_RULE_NUM 1024
enum {
IP6_PROTO,
@ -144,155 +145,363 @@ struct rte_acl_field_def ip6_defs[IP6_NUM] = {
RTE_ACL_RULE_DEF(acl6_rules, RTE_DIM(ip6_defs));
const struct acl6_rules acl6_rules_out[] = {
{
.data = {.userdata = PROTECT(5), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(6), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(10), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(11), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(25), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(26), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
}
};
struct acl6_rules acl6_rules_out[MAX_ACL_RULE_NUM];
uint32_t nb_acl6_rules_out;
const struct acl6_rules acl6_rules_in[] = {
{
.data = {.userdata = PROTECT(15), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x55555555, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(16), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x66666666, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(110), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x00000000, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(111), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0x11111111, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(125), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0xaaaaaaaa, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
},
{
.data = {.userdata = PROTECT(126), .category_mask = 1, .priority = 1},
/* destination IPv6 */
.field[5] = {.value.u32 = 0xffff0000, .mask_range.u32 = 32,},
.field[6] = {.value.u32 = 0x0, .mask_range.u32 = 32,},
.field[7] = {.value.u32 = 0xbbbbbbbb, .mask_range.u32 = 32,},
.field[8] = {.value.u32 = 0x0, .mask_range.u32 = 0,},
/* source port */
.field[9] = {.value.u16 = 0, .mask_range.u16 = 0xffff,},
/* destination port */
.field[10] = {.value.u16 = 0, .mask_range.u16 = 0xffff,}
struct acl6_rules acl6_rules_in[MAX_ACL_RULE_NUM];
uint32_t nb_acl6_rules_in;
void
parse_sp6_tokens(char **tokens, uint32_t n_tokens,
struct parse_status *status)
{
struct acl6_rules *rule_ipv6 = NULL;
uint32_t *ri = NULL; /* rule index */
uint32_t ti = 0; /* token index */
uint32_t esp_p = 0;
uint32_t protect_p = 0;
uint32_t bypass_p = 0;
uint32_t discard_p = 0;
uint32_t pri_p = 0;
uint32_t src_p = 0;
uint32_t dst_p = 0;
uint32_t proto_p = 0;
uint32_t sport_p = 0;
uint32_t dport_p = 0;
if (strcmp(tokens[1], "in") == 0) {
ri = &nb_acl6_rules_in;
APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
"many sp rules, abort insertion\n");
if (status->status < 0)
return;
rule_ipv6 = &acl6_rules_in[*ri];
} else if (strcmp(tokens[1], "out") == 0) {
ri = &nb_acl6_rules_out;
APP_CHECK(*ri <= MAX_ACL_RULE_NUM - 1, status, "too "
"many sp rules, abort insertion\n");
if (status->status < 0)
return;
rule_ipv6 = &acl6_rules_out[*ri];
} else {
APP_CHECK(0, status, "unrecognized input \"%s\", expect"
" \"in\" or \"out\"\n", tokens[ti]);
return;
}
};
rule_ipv6->data.category_mask = 1;
for (ti = 2; ti < n_tokens; ti++) {
if (strcmp(tokens[ti], "esp") == 0) {
/* currently do nothing */
APP_CHECK_PRESENCE(esp_p, tokens[ti], status);
if (status->status < 0)
return;
esp_p = 1;
continue;
}
if (strcmp(tokens[ti], "protect") == 0) {
APP_CHECK_PRESENCE(protect_p, tokens[ti], status);
if (status->status < 0)
return;
APP_CHECK(bypass_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"bypass");
if (status->status < 0)
return;
APP_CHECK(discard_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"discard");
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
if (status->status < 0)
return;
rule_ipv6->data.userdata =
PROTECT(atoi(tokens[ti]));
protect_p = 1;
continue;
}
if (strcmp(tokens[ti], "bypass") == 0) {
APP_CHECK_PRESENCE(bypass_p, tokens[ti], status);
if (status->status < 0)
return;
APP_CHECK(protect_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"protect");
if (status->status < 0)
return;
APP_CHECK(discard_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"discard");
if (status->status < 0)
return;
rule_ipv6->data.userdata = BYPASS;
bypass_p = 1;
continue;
}
if (strcmp(tokens[ti], "discard") == 0) {
APP_CHECK_PRESENCE(discard_p, tokens[ti], status);
if (status->status < 0)
return;
APP_CHECK(protect_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"protect");
if (status->status < 0)
return;
APP_CHECK(bypass_p == 0, status, "conflict item "
"between \"%s\" and \"%s\"", tokens[ti],
"discard");
if (status->status < 0)
return;
rule_ipv6->data.userdata = DISCARD;
discard_p = 1;
continue;
}
if (strcmp(tokens[ti], "pri") == 0) {
APP_CHECK_PRESENCE(pri_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK_TOKEN_IS_NUM(tokens, ti, status);
if (status->status < 0)
return;
rule_ipv6->data.priority = atoi(tokens[ti]);
pri_p = 1;
continue;
}
if (strcmp(tokens[ti], "src") == 0) {
struct in6_addr ip;
uint32_t depth;
APP_CHECK_PRESENCE(src_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
&depth) == 0, status, "unrecognized "
"input \"%s\", expect valid ipv6 "
"addr", tokens[ti]);
if (status->status < 0)
return;
rule_ipv6->field[1].value.u32 =
(uint32_t)ip.s6_addr[0] << 24 |
(uint32_t)ip.s6_addr[1] << 16 |
(uint32_t)ip.s6_addr[2] << 8 |
(uint32_t)ip.s6_addr[3];
rule_ipv6->field[1].mask_range.u32 =
(depth > 32) ? 32 : depth;
depth = (depth > 32) ? (depth - 32) : 0;
rule_ipv6->field[2].value.u32 =
(uint32_t)ip.s6_addr[4] << 24 |
(uint32_t)ip.s6_addr[5] << 16 |
(uint32_t)ip.s6_addr[6] << 8 |
(uint32_t)ip.s6_addr[7];
rule_ipv6->field[2].mask_range.u32 =
(depth > 32) ? 32 : depth;
depth = (depth > 32) ? (depth - 32) : 0;
rule_ipv6->field[3].value.u32 =
(uint32_t)ip.s6_addr[8] << 24 |
(uint32_t)ip.s6_addr[9] << 16 |
(uint32_t)ip.s6_addr[10] << 8 |
(uint32_t)ip.s6_addr[11];
rule_ipv6->field[3].mask_range.u32 =
(depth > 32) ? 32 : depth;
depth = (depth > 32) ? (depth - 32) : 0;
rule_ipv6->field[4].value.u32 =
(uint32_t)ip.s6_addr[12] << 24 |
(uint32_t)ip.s6_addr[13] << 16 |
(uint32_t)ip.s6_addr[14] << 8 |
(uint32_t)ip.s6_addr[15];
rule_ipv6->field[4].mask_range.u32 =
(depth > 32) ? 32 : depth;
src_p = 1;
continue;
}
if (strcmp(tokens[ti], "dst") == 0) {
struct in6_addr ip;
uint32_t depth;
APP_CHECK_PRESENCE(dst_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_ipv6_addr(tokens[ti], &ip,
&depth) == 0, status, "unrecognized "
"input \"%s\", expect valid ipv6 "
"addr", tokens[ti]);
if (status->status < 0)
return;
rule_ipv6->field[5].value.u32 =
(uint32_t)ip.s6_addr[0] << 24 |
(uint32_t)ip.s6_addr[1] << 16 |
(uint32_t)ip.s6_addr[2] << 8 |
(uint32_t)ip.s6_addr[3];
rule_ipv6->field[5].mask_range.u32 =
(depth > 32) ? 32 : depth;
depth = (depth > 32) ? (depth - 32) : 0;
rule_ipv6->field[6].value.u32 =
(uint32_t)ip.s6_addr[4] << 24 |
(uint32_t)ip.s6_addr[5] << 16 |
(uint32_t)ip.s6_addr[6] << 8 |
(uint32_t)ip.s6_addr[7];
rule_ipv6->field[6].mask_range.u32 =
(depth > 32) ? 32 : depth;
depth = (depth > 32) ? (depth - 32) : 0;
rule_ipv6->field[7].value.u32 =
(uint32_t)ip.s6_addr[8] << 24 |
(uint32_t)ip.s6_addr[9] << 16 |
(uint32_t)ip.s6_addr[10] << 8 |
(uint32_t)ip.s6_addr[11];
rule_ipv6->field[7].mask_range.u32 =
(depth > 32) ? 32 : depth;
depth = (depth > 32) ? (depth - 32) : 0;
rule_ipv6->field[8].value.u32 =
(uint32_t)ip.s6_addr[12] << 24 |
(uint32_t)ip.s6_addr[13] << 16 |
(uint32_t)ip.s6_addr[14] << 8 |
(uint32_t)ip.s6_addr[15];
rule_ipv6->field[8].mask_range.u32 =
(depth > 32) ? 32 : depth;
dst_p = 1;
continue;
}
if (strcmp(tokens[ti], "proto") == 0) {
uint16_t low, high;
APP_CHECK_PRESENCE(proto_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_range(tokens[ti], &low, &high)
== 0, status, "unrecognized input \"%s\""
", expect \"from:to\"", tokens[ti]);
if (status->status < 0)
return;
APP_CHECK(low <= 0xff, status, "proto low "
"over-limit");
if (status->status < 0)
return;
APP_CHECK(high <= 0xff, status, "proto high "
"over-limit");
if (status->status < 0)
return;
rule_ipv6->field[0].value.u8 = (uint8_t)low;
rule_ipv6->field[0].mask_range.u8 = (uint8_t)high;
proto_p = 1;
continue;
}
if (strcmp(tokens[ti], "sport") == 0) {
uint16_t port_low, port_high;
APP_CHECK_PRESENCE(sport_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_range(tokens[ti], &port_low,
&port_high) == 0, status, "unrecognized "
"input \"%s\", expect \"port_from:"
"port_to\"", tokens[ti]);
if (status->status < 0)
return;
rule_ipv6->field[9].value.u16 = port_low;
rule_ipv6->field[9].mask_range.u16 = port_high;
sport_p = 1;
continue;
}
if (strcmp(tokens[ti], "dport") == 0) {
uint16_t port_low, port_high;
APP_CHECK_PRESENCE(dport_p, tokens[ti], status);
if (status->status < 0)
return;
INCREMENT_TOKEN_INDEX(ti, n_tokens, status);
if (status->status < 0)
return;
APP_CHECK(parse_range(tokens[ti], &port_low,
&port_high) == 0, status, "unrecognized "
"input \"%s\", expect \"port_from:"
"port_to\"", tokens[ti]);
if (status->status < 0)
return;
rule_ipv6->field[10].value.u16 = port_low;
rule_ipv6->field[10].mask_range.u16 = port_high;
dport_p = 1;
continue;
}
/* unrecognizeable input */
APP_CHECK(0, status, "unrecognized input \"%s\"",
tokens[ti]);
return;
}
/* check if argument(s) are missing */
APP_CHECK(esp_p == 1, status, "missing argument \"esp\"");
if (status->status < 0)
return;
APP_CHECK(protect_p | bypass_p | discard_p, status, "missing "
"argument \"protect\", \"bypass\", or \"discard\"");
if (status->status < 0)
return;
*ri = *ri + 1;
}
static inline void
print_one_ip6_rule(const struct acl6_rules *rule, int32_t extra)
@ -407,11 +616,9 @@ acl6_init(const char *name, int32_t socketid, const struct acl6_rules *rules,
}
void
sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
sp6_init(struct socket_ctx *ctx, int32_t socket_id)
{
const char *name;
const struct acl6_rules *rules_out, *rules_in;
uint32_t nb_out_rules, nb_in_rules;
if (ctx == NULL)
rte_exit(EXIT_FAILURE, "NULL context.\n");
@ -424,25 +631,19 @@ sp6_init(struct socket_ctx *ctx, int32_t socket_id, uint32_t ep)
rte_exit(EXIT_FAILURE, "Outbound IPv6 SP DB for socket %u "
"already initialized\n", socket_id);
if (ep == 0) {
rules_out = acl6_rules_out;
nb_out_rules = RTE_DIM(acl6_rules_out);
rules_in = acl6_rules_in;
nb_in_rules = RTE_DIM(acl6_rules_in);
} else if (ep == 1) {
rules_out = acl6_rules_in;
nb_out_rules = RTE_DIM(acl6_rules_in);
rules_in = acl6_rules_out;
nb_in_rules = RTE_DIM(acl6_rules_out);
if (nb_acl6_rules_in > 0) {
name = "sp_ip6_in";
ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name,
socket_id, acl6_rules_in, nb_acl6_rules_in);
} else
rte_exit(EXIT_FAILURE, "Invalid EP value %u. "
"Only 0 or 1 supported.\n", ep);
RTE_LOG(WARNING, IPSEC, "No IPv6 SP Inbound rule "
"specified\n");
name = "sp_ip6_in";
ctx->sp_ip6_in = (struct sp_ctx *)acl6_init(name, socket_id,
rules_in, nb_in_rules);
name = "sp_ip6_out";
ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name, socket_id,
rules_out, nb_out_rules);
if (nb_acl6_rules_out > 0) {
name = "sp_ip6_out";
ctx->sp_ip6_out = (struct sp_ctx *)acl6_init(name,
socket_id, acl6_rules_out, nb_acl6_rules_out);
} else
RTE_LOG(WARNING, IPSEC, "No IPv6 SP Outbound rule "
"specified\n");
}