..
  # Copyright (c) 2023, Arm Limited.
  #
  # SPDX-License-Identifier: Apache-2.0

#################
SSL Reverse Proxy
#################

************
Introduction
************

A proxy server is a intermediary server that forwards requests for content from
clients to servers across network. A SSL reverse proxy is a type of proxy server
that controls Secure Sockets Layer (SSL) traffic to ensure secure transmission
of data between clients and servers. It acts as an intermediary, performing SSL
encryption and decryption between the client and the server. For client, it acts
as a server. For server, it acts as a client.

`wrk2`_ is a modern HTTP benchmarking tool capable of generating significant load
when runs on a single multi-core CPU. In this guide it is used to measure
the maximum requests per second (RPS) of the SSL reverse proxy on DUT node.
`NGINX`_ is open source software for web serving, reverse proxying, caching,
load balancing, media streaming, and more. In this guide one NGINX instance
acts as reverse proxy, and another NGINX instance acts as HTTPS server.

This guide explains in detail on how to integrate wrk2 and NGINX with VPP's
host stack for SSL proxy cases. The integration is done via LD_PRELOAD which
intercepts syscalls that are supposed to go into the kernel and reinjects
them into VPP. Users can execute bundled scripts in dataplane-stack repo to quickly
establish the SSL proxy cases or manually run the use cases by following detailed
guidelines step by step.

********************
Network Stack Layers
********************

.. figure:: ../images/nginx_kernel_vpp_stack.png
   :align: center

   Linux kernel stack VS VPP's host stack

VPP's host stack provides alternatives to kernel-based sockets so that applications
can take full advantage of VPP's high performance. It implements a clean slate TCP
that supports vectorized packet processing and follows VPP’s highly scalable threading
model. The implementation is RFC compliant and supports many high-speed TCP protocol
features. VPP's host stack also provides a transport pluggable session layer that
abstracts the interaction between applications and transports using a custom-built
shared memory infrastructure. There is also VPP Comms Library (VCL) included to ease
the consumability of the stack from application perspective. VCL manages the interaction
with the session layer, abstracts session to integer session handles and exposes its
own asynchronous communication functions.

This guide demonstrates two kinds of SSL reverse proxy connection:

- Loopback connection on DUT node
- Ethernet connection between DUT and client/server nodes

*******************
Loopback Connection
*******************

The loopback interface is a software virtual interface that is always up and available
after it has been configured. In this setup, NGINX HTTPS server, NGINX reverse proxy
and wrk2 client run over VPP's host stack on DUT and communicate with each other
through VPP loopback interfaces.

.. figure:: ../images/ssl_proxy_loop.png
   :align: center
   :width: 300

   Loopback connection

.. note::
        This setup requires four isolated cores. Cores 1-4 are assumed to be
        isolated in this guide. VPP, wrk2, NGINX HTTPS server and NGINX reverse
        proxy each require an isolated core.

Automated Execution
===================

Quickly set up VPP & NGINX and test SSL reverse proxy case:

.. code-block:: shell

        cd <nw_ds_workspace>/dataplane-stack
        ./usecase/ssl_reverse_proxy/run_vpp.sh -l -c 1
        ./usecase/ssl_reverse_proxy/run_nginx_server.sh -l -c 2
        ./usecase/ssl_reverse_proxy/run_nginx_proxy.sh -l -c 3
        ./usecase/ssl_reverse_proxy/run_wrk2.sh -l -c 4

.. note::
  -     You will be asked a series of questions in order to embed the information
        correctly in the certificate. Fill out the prompts appropriately.
  -     Use ``-h`` to check scripts supported options.

If the case runs successfully, the measurement results will be printed:

.. code-block:: none

        Initialised 1 threads in 0 ms.
        Running 1m test @ https://172.16.2.1:8089/1kb
          1 threads and 12 connections
          Thread calibration: mean lat.: 4989.234ms, rate sampling interval: 18006ms
          Thread Stats   Avg      Stdev     Max   +/- Stdev
            Latency    35.07s    14.40s    1.00m    57.95%
            Req/Sec    44.74k   112.00    44.86k    50.00%
          2691248 requests in 1.00m, 3.23GB read
        Requests/sec:  44854.12
        Transfer/sec:     55.05MB

Stop VPP and NGINX:

.. code-block:: shell

        ./usecase/ssl_reverse_proxy/stop.sh

Manual Execution
================

Users can also set up VPP & NGINX and test SSL reverse proxy case step by step.

VPP Setup
~~~~~~~~~

Declare a variable to hold the CLI socket for VPP:

.. code-block:: shell

        export sockfile="/run/vpp/cli.sock"

Run VPP as a daemon service on core 1 with session layer enabled.

.. code-block:: shell

        cd <nw_ds_workspace>/dataplane-stack/components/vpp/build-root/install-vpp-native/vpp/bin
        sudo ./vpp unix {cli-listen ${sockfile}} cpu {main-core 1} tcp {cc-algo cubic} session {enable use-app-socket-api} plugins {plugin dpdk_plugin.so {disable}}

For more configuration parameters, refer to `VPP configuration reference`_.

Create loopback interfaces and routes by following VPP commands:

.. code-block:: none

        sudo ./vppctl -s ${sockfile} create loopback interface
        sudo ./vppctl -s ${sockfile} set interface state loop0 up
        sudo ./vppctl -s ${sockfile} create loopback interface
        sudo ./vppctl -s ${sockfile} set interface state loop1 up
        sudo ./vppctl -s ${sockfile} create loopback interface
        sudo ./vppctl -s ${sockfile} set interface state loop2 up
        sudo ./vppctl -s ${sockfile} ip table add 1
        sudo ./vppctl -s ${sockfile} set interface ip table loop0 1
        sudo ./vppctl -s ${sockfile} ip table add 2
        sudo ./vppctl -s ${sockfile} set interface ip table loop1 2
        sudo ./vppctl -s ${sockfile} ip table add 3
        sudo ./vppctl -s ${sockfile} set interface ip table loop2 3
        sudo ./vppctl -s ${sockfile} set interface ip address loop0 172.16.1.1/24
        sudo ./vppctl -s ${sockfile} set interface ip address loop1 172.16.2.1/24
        sudo ./vppctl -s ${sockfile} set interface ip address loop2 172.16.3.1/24
        sudo ./vppctl -s ${sockfile} app ns add id server secret 1234 if loop0
        sudo ./vppctl -s ${sockfile} app ns add id proxy secret 1234 if loop1
        sudo ./vppctl -s ${sockfile} app ns add id client secret 1234 if loop2
        sudo ./vppctl -s ${sockfile} ip route add 172.16.1.1/32 table 2 via lookup in table 1
        sudo ./vppctl -s ${sockfile} ip route add 172.16.3.1/32 table 2 via lookup in table 3
        sudo ./vppctl -s ${sockfile} ip route add 172.16.2.1/32 table 1 via lookup in table 2
        sudo ./vppctl -s ${sockfile} ip route add 172.16.2.1/32 table 3 via lookup in table 2

For more detailed usage on above commands, refer to the following links:

- `VPP set interface ip address reference`_
- `VPP set interface state reference`_
- `VPP ip route reference`_
- `VPP app ns reference`_

To explore more on VPP's available commands, please review `VPP CLI reference`_.

Declare a variable to hold the ``LD_PRELOAD`` library for VCL:

.. code-block:: shell

        export LDP_PATH="<nw_ds_workspace>/dataplane-stack/components/vpp/build-root/install-vpp-native/vpp/lib/aarch64-linux-gnu/libvcl_ldpreload.so"

.. note::

   Any use of ``~`` in ``LDP_PATH`` will expand to the root user's home directory when used later in the guide.

NGINX Setup
~~~~~~~~~~~

1. VCL parameters can be configured through VCL configuration file. A VCL configuration
   sample for NGINX HTTPS server is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_nginx_server.conf``
   with the following contents:

   .. code-block:: none

        vcl {
          heapsize 64M
          segment-size 4000000000
          add-segment-size 4000000000
          rx-fifo-size 4000000
          tx-fifo-size 4000000
          namespace-id server
          namespace-secret 1234
          app-scope-global
          app-socket-api /var/run/vpp/app_ns_sockets/server
        }

2. A VCL configuration sample for NGINX reverse proxy is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_nginx_proxy.conf``
   with the following contents:

   .. code-block:: none

        vcl {
          heapsize 64M
          segment-size 4000000000
          add-segment-size 4000000000
          rx-fifo-size 4000000
          tx-fifo-size 4000000
          namespace-id proxy
          namespace-secret 1234
          app-scope-global
          app-socket-api /var/run/vpp/app_ns_sockets/proxy
        }

The above files configure VCL to request 4MB receive and transmit FIFO sizes and
access to global session scope. They also provide the path to VPP's session layer
socket API for NGINX instances. Refer to `VPP VCL reference`_ for more usage
information on VCL parameters.

3. Create SSL private keys and certificates for NGINX HTTPS server and reverse proxy:

   .. code-block:: shell

        sudo mkdir -p /etc/nginx/certs
        sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/server.key -out /etc/nginx/certs/server.crt
        sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/proxy.key -out /etc/nginx/certs/proxy.crt

   .. note::

        You will be asked a series of questions in order to embed the information
        correctly in the certificate. Fill out the prompts appropriately.

4. The way NGINX works is determined in the NGINX configuration file. A NGINX configuration
   sample for NGINX HTTPS server is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_server.conf``
   with the following contents:

   .. _nginx https server config:
   .. code-block:: none

        worker_processes 1;
        pid /run/nginx_server.pid;

        events {}

        http {
                sendfile on;
                tcp_nopush on;
                keepalive_requests 1000000000;

                default_type application/octet-stream;

                access_log off;
                error_log /dev/null crit;

                server {
                        listen 8445 ssl;
                        server_name $hostname;
                        ssl_protocols TLSv1.3;
                        ssl_prefer_server_ciphers on;
                        ssl_certificate /etc/nginx/certs/server.crt;
                        ssl_certificate_key /etc/nginx/certs/server.key;
                        root /var/www/html;

                        location / {
                                try_files $uri $uri/ =404;
                        }
                }
        }

5. A NGINX configuration sample for NGINX reverse proxy is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_proxy.conf``
   with the following contents:

   .. _nginx reverse proxy config:
   .. code-block:: none

        worker_processes 1;
        pid /run/nginx_proxy.pid;

        events {}

        http {
                sendfile on;
                tcp_nopush on;
                keepalive_requests 1000000000;

                default_type application/octet-stream;

                access_log off;
                error_log /dev/null crit;

                upstream ssl_file_server_com {
                        server 172.16.1.1:8445;
                        keepalive 1024;
                }

                server {
                        listen 8089 ssl;
                        server_name $hostname;
                        ssl_protocols TLSv1.3;
                        ssl_prefer_server_ciphers on;
                        ssl_certificate /etc/nginx/certs/proxy.crt;
                        ssl_certificate_key /etc/nginx/certs/proxy.key;

                        location / {
                                limit_except GET {
                                deny all;
                                }
                                proxy_pass https://ssl_file_server_com;
                                proxy_http_version 1.1;
                                proxy_set_header Connection "";
                                proxy_ssl_protocols TLSv1.3;
                        }
                }
        }


For more detailed usage on above NGINX configuration, refer to the following links:

- `NGINX core functionality reference`_
- `NGINX HTTP core module reference`_
- `NGINX HTTP upstream module reference`_
- `NGINX HTTP proxy module reference`_
- `NGINX HTTP SSL module reference`_

6. Create a 1kb file in NGINX HTTPS server root directory for downloading:

   .. code-block:: shell

        sudo mkdir -p /var/www/html
        sudo dd if=/dev/urandom of=/var/www/html/1kb bs=1024 count=1

7. ``VCL_CONFIG`` provides VCL with a configuration file to read during startup. Start
   the NGINX HTTPS server on core 2 over VPP's host stack, providing with the
   VCL and NGINX configuration files:

   .. code-block:: shell

        sudo taskset -c 2 sh -c "LD_PRELOAD=${LDP_PATH} \
             VCL_CONFIG=<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_nginx_server.conf \
             nginx -c <nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_server.conf"

8. Start the NGINX reverse proxy on core 3 over VPP's host stack, providing with
   the VCL and NGINX configuration files:

   .. code-block:: shell

        sudo taskset -c 3 sh -c "LD_PRELOAD=${LDP_PATH} \
             VCL_CONFIG=<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_nginx_proxy.conf \
             nginx -c <nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_proxy.conf"

9. To examine the NGINX sessions in VPP, use the command ``sudo ./vppctl -s ${sockfile} show session verbose``.
   Here is a sample output for NGINX sessions:

   .. code-block:: none

        Connection                                                  State          Rx-f      Tx-f
        [0:0][T] 172.16.2.1:8089->0.0.0.0:0                         LISTEN         0         0
        [0:1][T] 172.16.1.1:8445->0.0.0.0:0                         LISTEN         0         0
        Thread 0: active sessions 2

Test
~~~~

A VCL configuration sample for wrk2 HTTPS client is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_wrk2.conf``
with the following contents:

.. code-block:: none

        vcl {
          heapsize 64M
          segment-size 4000000000
          add-segment-size 4000000000
          rx-fifo-size 4000000
          tx-fifo-size 4000000
          namespace-id client
          namespace-secret 1234
          use-mq-eventfd
          app-scope-global
          app-socket-api /var/run/vpp/app_ns_sockets/client
        }

Run wrk2 client on core 4 over VPP's host stack to test SSL reverse proxy with 1kb
file downloading:

.. code-block:: shell

        cd <nw_ds_workspace>/dataplane-stack/tools/traffic-gen/wrk2-aarch64
        sudo taskset -c 4 sh -c "LD_PRELOAD=${LDP_PATH} \
            VCL_CONFIG=<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_wrk2.conf \
            ./wrk --rate 100000000 -t 1 -c 12 -d 60s https://172.16.2.1:8089/1kb"

.. note::
  -     Extremely high rate ``--rate`` is used to ensure throughput is measured.
  -     Number of connections ``-c`` is set to 12 to produce high throughput. For
        connection number less than 12, there are some socket connect or timeout
        errors which may block the test.
  -     Test duration ``-d`` is 60 seconds to get stable and repeatable results.
  -     URL is NGINX reverse proxy's URL to be tested.

If both wrk2 and NGINX run successfully, wrk2 will output measurement result similar
to the following:

.. code-block:: none

        Initialised 1 threads in 0 ms.
        Running 1m test @ https://172.16.2.1:8089/1kb
          1 threads and 12 connections
          Thread calibration: mean lat.: 4989.234ms, rate sampling interval: 18006ms
          Thread Stats   Avg      Stdev     Max   +/- Stdev
            Latency    35.07s    14.40s    1.00m    57.95%
            Req/Sec    44.74k   112.00    44.86k    50.00%
          2691248 requests in 1.00m, 3.23GB read
        Requests/sec:  44854.12
        Transfer/sec:     55.05MB

Stop
~~~~

Kill VPP:

.. code-block:: shell

        sudo pkill -9 vpp

Kill NGINX instances:

.. code-block:: shell

        sudo pkill -9 nginx

*******************
Ethernet Connection
*******************

In this SSL reverse proxy scenario, NGINX HTTPS server, NGINX reverse proxy and
wrk2 HTTPS client run on separated hardware platforms. The DUT has one NIC interface
connected with the server node, and another NIC interface connected with the client node.
NGINX reverse proxy runs over VPP's host stack on DUT. NGINX HTTPS server runs over Linux
kernel stack on server node. wrk2 HTTPS client runs over Linux kernel stack on client node.

.. figure:: ../images/ssl_proxy_dpdk.png
   :align: center
   :width: 450

   Ethernet connection

To find out which DUT interfaces are connected with HTTPS client/server nodes,
``sudo ethtool --identify <interface_name>`` will typically blink a light on the
NIC to help identify the physical port associated with the interface.

Get interface names and PCIe addresses from ``lshw`` command:

.. code-block:: shell

        sudo lshw -c net -businfo

The output will look similar to:

.. code-block:: none

        Bus info          Device      Class      Description
        ====================================================
        pci@0000:07:00.0  eth0        network    RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller
        pci@0001:01:00.0  enP1p1s0f0  network    MT27800 Family [ConnectX-5]
        pci@0001:01:00.1  enP1p1s0f1  network    MT27800 Family [ConnectX-5]

In this setup example, ``enP1p1s0f0`` at PCIe address ``0001:01:00.0`` is used to
connect with the client node. The IP address of this NIC interface in VPP is configured
as 172.16.2.1/24. ``enP1p1s0f1`` at PCIe address ``0001:01:00.1`` is used to connect
with the server node. The IP address of this NIC interface in VPP is configured
as 172.16.1.2/24. The IP address of the client node NIC is 172.16.2.2/24. The IP address
of the server node NIC is 172.16.1.1/24.

Install git and building tools on the client node. If running Ubuntu 20.04 or later,
``apt install git build-essential`` will be sufficient. For other Linux distributions,
please consult the package manager for equivalent one.

Install NGINX on the server node. If running Ubuntu 20.04 or later, ``apt install nginx``
will be sufficient. For other Linux distributions, please consult the package manager.
Follow :ref:`repo download target` to download dataplane-stack repo on the server node to
ease NGINX HTTPS server setup.

Automated Execution
===================

Quickly set up VPP and NGINX reverse proxy on the DUT:

.. code-block:: shell

        cd <nw_ds_workspace>/dataplane-stack
        ./usecase/ssl_reverse_proxy/run_vpp.sh -p 0001:01:00.0,0001:01:00.1 -c 1
        ./usecase/ssl_reverse_proxy/run_nginx_proxy.sh -p -c 2

.. note::
  -     Replace sample addresses in above command with desired PCIe addresses on DUT.
  -     You will be asked a series of questions in order to embed the information
        correctly in the certificate. Fill out the prompts appropriately.

On the server node, start NGINX HTTPS server:

.. code-block:: shell

        cd <nw_ds_workspace>/dataplane-stack
        ./usecase/ssl_reverse_proxy/run_nginx_server.sh -p -c 1

.. note::
        Core 1 is assumed to be isolated on the server node.

On the client node, download, build and run wrk2 to test SSL reverse proxy:

.. tabs::

    .. code-tab:: shell x86

        git clone https://github.com/giltene/wrk2.git
        cd wrk2
        make all
        sudo taskset -c 1 ./wrk --rate 100000000 -t 1 -c 12 -d 60s https://172.16.2.1:8089/1kb

    .. code-tab:: shell AArch64

        git clone https://github.com/AmpereTravis/wrk2-aarch64.git
        cd wrk2-aarch64
        make all
        sudo taskset -c 1 ./wrk --rate 100000000 -t 1 -c 12 -d 60s https://172.16.2.1:8089/1kb

.. note::
        Core 1 is assumed to be isolated on the client node.

If the case runs successfully, the measurement results will be printed by wrk2 client:

.. code-block:: none

        Initialised 1 threads in 0 ms.
        Running 1m test @ https://172.16.2.1:8089/1kb
          1 threads and 12 connections
          Thread calibration: mean lat.: 5043.897ms, rate sampling interval: 18104ms
          Thread Stats   Avg      Stdev     Max   +/- Stdev
            Latency    35.19s    14.41s    1.00m    57.64%
            Req/Sec    35.97k   144.00    36.12k    50.00%
          2165247 requests in 1.00m, 2.60GB read
        Requests/sec:  36087.22
        Transfer/sec:     44.29MB

Stop VPP and NGINX on DUT:

.. code-block:: shell

        ./usecase/ssl_reverse_proxy/stop.sh

Stop NGINX on server node:

.. code-block:: shell

        ./usecase/ssl_reverse_proxy/stop.sh

Manual Execution
================

Users can also set up VPP & NGINX and test SSL reverse proxy case step by step.

DUT VPP Setup
~~~~~~~~~~~~~

Declare a variable to hold the CLI socket for VPP:

.. code-block:: shell

        export sockfile="/run/vpp/cli.sock"

Run VPP as a daemon service on core 1 with interface PCIe addresses and session layer enabled:

.. code-block:: shell

        cd <nw_ds_workspace>/dataplane-stack/components/vpp/build-root/install-vpp-native/vpp/bin
        sudo ./vpp unix {cli-listen ${sockfile}} cpu {main-core 1} tcp {cc-algo cubic} dpdk {dev 0001:01:00.0 {name eth0} dev 0001:01:00.1 {name eth1}} session {enable use-app-socket-api}

.. note::
        Replace sample addresses in above command with desired PCIe addresses on DUT.

Bring two VPP Ethernet interfaces up and set IP addresses:

.. code-block:: shell

        sudo ./vppctl -s ${sockfile} set interface state eth0 up
        sudo ./vppctl -s ${sockfile} set interface ip address eth0 172.16.2.1/24
        sudo ./vppctl -s ${sockfile} set interface state eth1 up
        sudo ./vppctl -s ${sockfile} set interface ip address eth1 172.16.1.2/24

Declare a variable to hold the VPP library for ``LD_PRELOAD``:

.. code-block:: shell

        export LDP_PATH="<nw_ds_workspace>/dataplane-stack/components/vpp/build-root/install-vpp-native/vpp/lib/aarch64-linux-gnu/libvcl_ldpreload.so"

.. note::

   Any use of ``~`` in ``LDP_PATH`` will expand to the root user's home directory when used later in the guide.

DUT NGINX Setup
~~~~~~~~~~~~~~~

1. Create SSL private key and certificate for NGINX reverse proxy:

   .. code-block:: shell

        sudo mkdir -p /etc/nginx/certs
        sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/proxy.key -out /etc/nginx/certs/proxy.crt

   .. note::
        You will be asked a series of questions in order to embed the information
        correctly in the certificate. Fill out the prompts appropriately.

2. A NGINX configuration sample for NGINX reverse proxy is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_proxy.conf``
   with :ref:`these contents <nginx reverse proxy config>`.

   .. note::
        The NGINX HTTPS server ``IP address:listening port`` should be used as the
        server field in upstream section of above configuration file. For this setup
        example, ``172.16.1.1:8445`` is used.

3. A VCL configuration sample for NGINX reverse proxy is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_nginx_proxy_pn.conf``
   with the following contents:

   .. code-block:: none

        vcl {
          heapsize 64M
          segment-size 4000000000
          add-segment-size 4000000000
          rx-fifo-size 4000000
          tx-fifo-size 4000000
          app-socket-api /var/run/vpp/app_ns_sockets/default
        }

   The above configures VCL to request 4MB receive and transmit FIFO sizes and
   provides the path to VPP's session layer socket API. Refer to `VPP VCL reference`_
   for more usage information on VCL parameters.

4. ``VCL_CONFIG`` provides VCL with a configuration file to read during startup. Start
   the NGINX reverse proxy on core 2 over VPP's host stack, providing with the
   VCL and NGINX configuration files:

   .. code-block:: shell

        sudo taskset -c 2 sh -c "LD_PRELOAD=${LDP_PATH} \
             VCL_CONFIG=<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/vcl_nginx_proxy_pn.conf \
             nginx -c <nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_proxy.conf"

5. To examine the NGINX proxy session in VPP, run the command ``sudo ./vppctl -s ${sockfile} show session verbose``.
   Here is a sample output for NGINX proxy session:

  .. code-block:: none

        Connection                                                  State          Rx-f      Tx-f
        [0:0][T] 0.0.0.0:8089->0.0.0.0:0                         LISTEN         0         0
        Thread 0: active sessions 1

NGINX Setup on Server Node
~~~~~~~~~~~~~~~~~~~~~~~~~~

1. On the server node, create SSL private key and certificate for NGINX HTTPS server:

   .. code-block:: shell

        sudo mkdir -p /etc/nginx/certs
        sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/certs/server.key -out /etc/nginx/certs/server.crt

   .. note::
        You will be asked a series of questions in order to embed the information
        correctly in the certificate. Fill out the prompts appropriately.

2. Create a 1kb file in NGINX HTTPS server root directory for downloading:

   .. code-block:: shell

        sudo mkdir -p /var/www/html
        sudo dd if=/dev/urandom of=/var/www/html/1kb bs=1024 count=1

3. A NGINX configuration sample for NGINX HTTPS server is provided at ``<nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_server.conf``
   with :ref:`these contents <nginx https server config>`.

4. Start NGINX HTTPS server on core 1:

   .. code-block:: shell

        sudo taskset -c 1 nginx -c <nw_ds_workspace>/dataplane-stack/usecase/ssl_reverse_proxy/nginx_server.conf

   .. note::
        Core 1 is assumed to be isolated on the server node.

Test
~~~~

On the client node, download, build and run wrk2 to test SSL reverse proxy case:

.. tabs::

    .. code-tab:: shell x86

        git clone https://github.com/giltene/wrk2.git
        cd wrk2
        make all
        sudo taskset -c 1 ./wrk --rate 100000000 -t 1 -c 12 -d 60s https://172.16.2.1:8089/1kb

    .. code-tab:: shell AArch64

        git clone https://github.com/AmpereTravis/wrk2-aarch64.git
        cd wrk2-aarch64
        make all
        sudo taskset -c 1 ./wrk --rate 100000000 -t 1 -c 12 -d 60s https://172.16.2.1:8089/1kb

.. note::
        Core 1 is assumed to be isolated on the client node.

If both wrk2 and NGINX run successfully, wrk2 will output measurement result similar
to the following:

.. code-block:: none

        Initialised 1 threads in 0 ms.
        Running 1m test @ https://172.16.2.1:8089/1kb
          1 threads and 12 connections
          Thread calibration: mean lat.: 5043.897ms, rate sampling interval: 18104ms
          Thread Stats   Avg      Stdev     Max   +/- Stdev
            Latency    35.19s    14.41s    1.00m    57.64%
            Req/Sec    35.97k   144.00    36.12k    50.00%
          2165247 requests in 1.00m, 2.60GB read
        Requests/sec:  36087.22
        Transfer/sec:     44.29MB

Stop
~~~~

Kill VPP on DUT:

.. code-block:: shell

        sudo pkill -9 vpp

Kill NGINX on DUT and server nodes:

.. code-block:: shell

        sudo pkill -9 nginx

*********
Resources
*********

#. `wrk2 <https://github.com/giltene/wrk2>`_
#. `NGINX <https://www.nginx.com/resources/glossary/nginx/>`_
#. `VPP configuration reference <https://s3-docs.fd.io/vpp/23.02/configuration/reference.html>`_
#. `VPP set interface ip address reference <https://s3-docs.fd.io/vpp/23.02/cli-reference/clis/clicmd_src_vnet_ip.html#set-interface-ip-address>`_
#. `VPP set interface state reference <https://s3-docs.fd.io/vpp/23.02/cli-reference/clis/clicmd_src_vnet.html#set-interface-state>`_
#. `VPP ip route reference <https://s3-docs.fd.io/vpp/23.02/cli-reference/clis/clicmd_src_vnet_ip.html#ip-route>`_
#. `VPP app ns reference <https://s3-docs.fd.io/vpp/23.02/cli-reference/clis/clicmd_src_vnet_session.html#app-ns>`_
#. `VPP CLI reference <https://s3-docs.fd.io/vpp/23.02/cli-reference/index.html>`_
#. `VPP VCL reference <https://wiki.fd.io/view/VPP/HostStack/VCL>`_
#. `NGINX core functionality reference <https://nginx.org/en/docs/ngx_core_module.html>`_
#. `NGINX HTTP core module reference <https://nginx.org/en/docs/http/ngx_http_core_module.html>`_
#. `NGINX HTTP upstream module reference <https://nginx.org/en/docs/http/ngx_http_upstream_module.html>`_
#. `NGINX HTTP proxy module reference <https://nginx.org/en/docs/http/ngx_http_proxy_module.html>`_
#. `NGINX HTTP SSL module reference <https://nginx.org/en/docs/http/ngx_http_ssl_module.html>`_