libmemif: refactor examples

- icmp_responder: responds to ICMPv4 and ARP requests
- loopback: connects two interfaces and sends a
  verification packet from master memif to slave memif
  where it is looped back
- loopback (reverse path): reverses direction of packet
  in loopback application (slave memif to master memif)

Type: refactor

Signed-off-by: Jakub Grajciar <jgrajcia@cisco.com>
Change-Id: Ie90aaa3367269408efb6c5d538ad5aa827432238
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
This commit is contained in:
Jakub Grajciar
2021-01-04 11:28:33 +01:00
committed by Damjan Marion
parent 7d6f7d0d67
commit e74c04fc9f
19 changed files with 1838 additions and 329 deletions

View File

@ -67,8 +67,6 @@ ifeq ($(OS_ID),ubuntu)
sudo apt-get update; \
sudo apt-get $(CONFIRM) $(FORCE) install $$inst; \
fi
else ifneq ("$(wildcard /etc/redhat-release)","")
@sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS)
endif
.PHONY: spell

View File

@ -21,7 +21,7 @@ import subprocess
# -- Project information -----------------------------------------------------
project = u'The Vector Packet Processor'
copyright = u'2018-2021, Linux Foundation'
copyright = u'2018-2022, Linux Foundation'
author = u'FD.io VPP Community'
# The short X.Y version

View File

@ -1 +0,0 @@
../../../extras/libmemif/examples/example_setup_doc.rst

View File

@ -19,6 +19,5 @@ packets using libmemif API.
libmemif_doc
buildinstructions_doc
example_setup_doc
examples_doc
gettingstarted_doc
examples_doc

View File

@ -1,20 +1,20 @@
FROM ubuntu:xenial
RUN apt-get update && \
apt-get install -y git build-essential autoconf pkg-config libtool sudo check
apt-get install -y git build-essential autoconf pkg-config libtool sudo
RUN rm -rf /var/lib/apt/lists/*
RUN mkdir /libmemif
ADD . /libmemif
WORKDIR /libmemif
RUN ./bootstrap
RUN ./configure
RUN mkdir build
RUN cmake ..
WORKDIR /libmemif/build
RUN make
RUN make install
RUN mkdir /run/vpp
RUN ulimit -c unlimited
CMD ./.libs/icmpr-epoll
CMD ./examples/icmp_responder

View File

@ -8,54 +8,50 @@ Install dependencies
::
# sudo apt-get install -y git cmake autoconf pkg_config libtool
sudo apt-get install -y git cmake autoconf pkg_config libtool
Libmemif is now part of VPP repository. Follow fd.io wiki to pull source
code from VPP repository.
https://wiki.fd.io/view/VPP/Pulling,_Building,_Running,_Hacking_and_Pushing_VPP_Code#Pushing_Patches
Libmemif is located under extras/libmemif. From extras/libmemif:
Libmemif is located under extras/libmemif. From the vpp workspace root directory::
::
# mkdir build
# cd build
# cmake ..
# make install
mkdir -p extras/libmemif/build
cd extras/libmemif/build
cmake ..
make install
Verify installation:
--------------------
::
build# ./examples/icmp_responder -?
./examples/icmp_responder -?
Use ``-?`` flag to display help:
Use ``-?`` flag to display help::
::
LIBMEMIF EXAMPLE APP: icmp_responder_example
==============================
libmemif version: 4.0, memif version: 2.0
==============================
In this example, memif endpoint connects to an external application.
The example application can resolve ARP and reply to ICMPv4 packets.
The program will exit once the interface is disconnected.
==============================
Usage: icmp_responder [OPTIONS]
LIBMEMIF EXAMPLE APP: icmp_responder_example
==============================
libmemif version: 4.0, memif version: 2.0
==============================
In this example, memif endpoint connects to an external application.
The example application can resolve ARP and reply to ICMPv4 packets.
The program will exit once the interface is disconnected.
==============================
Usage: icmp_responder [OPTIONS]
Options:
-r Interface role <slave|master>. Default: slave
-s Socket path. Supports abstract socket using @ before the path. Default: /run/vpp/memif.sock
-i Interface id. Default: 0
-a IPv4 address. Default: 192.168.1.1
-h Mac address. Default: aa:aa:aa:aa:aa:aa
-? Show help and exit.
-v Show libmemif and memif version information and exit.
Options:
-r Interface role <slave|master>. Default: slave
-s Socket path. Supports abstract socket using @ before the path. Default: /run/vpp/memif.sock
-i Interface id. Default: 0
-a IPv4 address. Default: 192.168.1.1
-h Mac address. Default: aa:aa:aa:aa:aa:aa
-? Show help and exit.
-v Show libmemif and memif version information and exit.
Use Cases
---------
Examples
--------
Once the library is built/installed, refer to :ref:`libmemif_examples_doc`
and :ref:`libmemif_gettingstarted_doc` for additional information on basic
use cases and API usage.
Once the library is built/installed, refer to :ref:`libmemif_gettingstarted_doc`
and :ref:`libmemif_examples_doc` for additional information on basic use cases
and API usage.

View File

@ -13,20 +13,25 @@
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
set(HEADERS_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(COMMON_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/common)
set(COMMON_SOURCE_FILES
common/common.c
common/sender.c
common/responder.c
common/packet_handler.c
common/icmp_proto.c
)
list(APPEND EXAMPLES_LIST
loopback/main.c
icmp_responder/main.c
)
foreach (EXAMPLE_SRC ${EXAMPLES_LIST})
string(FIND ${EXAMPLE_SRC} "/" INDEX)
string(SUBSTRING ${EXAMPLE_SRC} 0 ${INDEX} EXECUTABLE)
add_executable(${EXECUTABLE} ${COMMON_SOURCE_FILES} ${EXAMPLE_SRC})
target_include_directories(${EXECUTABLE} PRIVATE $<BUILD_INTERFACE:${HEADERS_DIR}>)
add_executable(${EXECUTABLE} ${COMMON_SOURCE_FILES} ${EXAMPLE_SRC} )
target_include_directories(${EXECUTABLE} PRIVATE $<BUILD_INTERFACE:${COMMON_HEADERS}>)
target_link_libraries(${EXECUTABLE} memif ${CMAKE_THREAD_LIBS_INIT})
endforeach()

View File

@ -0,0 +1,192 @@
#include <common.h>
void
print_memif_ring_details (memif_connection_t *c, uint16_t qid, uint8_t is_rx)
{
/* TODO: print memif shared memory details */
}
void
print_memif_rx_ring_details (memif_connection_t *c, uint16_t qid)
{
print_memif_ring_details (c, qid, /* RX */ 1);
}
void
print_memif_tx_ring_details (memif_connection_t *c, uint16_t qid)
{
print_memif_ring_details (c, qid, /* TX */ 0);
}
void
print_version ()
{
printf ("libmemif version: %s, memif version: %s\n", LIBMEMIF_VERSION,
memif_get_version_str ());
}
int
parse_ip4 (const char *input, uint8_t out[4])
{
char *ui, *end;
char *tmp = strdup (input);
ui = strtok (tmp, ".");
if (ui == NULL)
return -1;
out[0] = strtol (ui, &end, 10);
ui = strtok (NULL, ".");
if (ui == NULL)
return -1;
out[1] = strtol (ui, &end, 10);
ui = strtok (NULL, ".");
if (ui == NULL)
return -1;
out[2] = strtol (ui, &end, 10);
ui = strtok (NULL, ".");
if (ui == NULL)
return -1;
out[3] = strtol (ui, &end, 10);
free (tmp);
return 0;
}
int
parse_mac (const char *input, uint8_t out[6])
{
char *ui, *end;
char *tmp = strdup (input);
ui = strtok (tmp, ":");
if (ui == NULL)
return -1;
out[0] = strtol (ui, &end, 16);
ui = strtok (NULL, ":");
if (ui == NULL)
return -1;
out[1] = strtol (ui, &end, 16);
ui = strtok (NULL, ":");
if (ui == NULL)
return -1;
out[2] = strtol (ui, &end, 16);
ui = strtok (NULL, ":");
if (ui == NULL)
return -1;
out[3] = strtol (ui, &end, 16);
ui = strtok (NULL, ":");
if (ui == NULL)
return -1;
out[4] = strtol (ui, &end, 16);
ui = strtok (NULL, ":");
if (ui == NULL)
return -1;
out[5] = strtol (ui, &end, 16);
free (tmp);
return 0;
}
void
alloc_memif_buffers (memif_connection_t *c)
{
c->rx_bufs =
(memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
c->rx_buf_num = 0;
c->tx_bufs =
(memif_buffer_t *) malloc (sizeof (memif_buffer_t) * MAX_MEMIF_BUFS);
c->tx_buf_num = 0;
}
void
free_memif_buffers (memif_connection_t *c)
{
if (c->rx_bufs != NULL)
free (c->rx_bufs);
c->rx_bufs = NULL;
c->rx_buf_num = 0;
if (c->tx_bufs != NULL)
free (c->tx_bufs);
c->tx_bufs = NULL;
c->tx_buf_num = 0;
}
void
print_memif_details (memif_connection_t *c)
{
printf ("MEMIF DETAILS\n");
printf ("==============================\n");
memif_details_t md;
memset (&md, 0, sizeof (md));
ssize_t buflen = 2048;
char *buf = (char *) malloc (buflen);
memset (buf, 0, buflen);
int err, e;
err = memif_get_details (c->conn, &md, buf, buflen);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("%s", memif_strerror (err));
if (err == MEMIF_ERR_NOCONN)
{
free (buf);
return;
}
}
printf ("\tinterface name: %s\n", (char *) md.if_name);
printf ("\tapp name: %s\n", (char *) md.inst_name);
printf ("\tremote interface name: %s\n", (char *) md.remote_if_name);
printf ("\tremote app name: %s\n", (char *) md.remote_inst_name);
printf ("\tid: %u\n", md.id);
printf ("\tsecret: %s\n", (char *) md.secret);
printf ("\trole: ");
if (md.role)
printf ("slave\n");
else
printf ("master\n");
printf ("\tmode: ");
switch (md.mode)
{
case 0:
printf ("ethernet\n");
break;
case 1:
printf ("ip\n");
break;
case 2:
printf ("punt/inject\n");
break;
default:
printf ("unknown\n");
break;
}
printf ("\tsocket path: %s\n", (char *) md.socket_path);
printf ("\trx queues:\n");
for (e = 0; e < md.rx_queues_num; e++)
{
printf ("\t\tqueue id: %u\n", md.rx_queues[e].qid);
printf ("\t\tring size: %u\n", md.rx_queues[e].ring_size);
printf ("\t\tbuffer size: %u\n", md.rx_queues[e].buffer_size);
}
printf ("\ttx queues:\n");
for (e = 0; e < md.tx_queues_num; e++)
{
printf ("\t\tqueue id: %u\n", md.tx_queues[e].qid);
printf ("\t\tring size: %u\n", md.tx_queues[e].ring_size);
printf ("\t\tbuffer size: %u\n", md.tx_queues[e].buffer_size);
}
printf ("\tlink: ");
if (md.link_up_down)
printf ("up\n");
else
printf ("down\n");
free (buf);
}

View File

@ -0,0 +1,116 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#ifndef _COMMON_H_
#define _COMMON_H_
#include <libmemif.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#ifdef ICMP_DBG
#define DBG(...) \
do \
{ \
printf (APP_NAME ":%s:%d: ", __func__, __LINE__); \
printf (__VA_ARGS__); \
printf ("\n"); \
} \
while (0)
#else
#define DBG(...)
#endif
#define INFO(...) \
do \
{ \
printf ("INFO: " __VA_ARGS__); \
printf ("\n"); \
} \
while (0)
/* maximum tx/rx memif buffers */
#define MAX_MEMIF_BUFS 256
struct memif_connection;
typedef int (memif_packet_handler_t) (struct memif_connection *conn);
typedef int (packet_generator_t) (struct memif_connection *c,
uint16_t num_pkts);
typedef struct memif_connection
{
uint16_t index;
/* memif conenction handle */
memif_conn_handle_t conn;
uint8_t is_connected;
/* transmit queue id */
uint16_t tx_qid;
/* tx buffers */
memif_buffer_t *tx_bufs;
/* allocated tx buffers counter */
/* number of tx buffers pointing to shared memory */
uint16_t tx_buf_num;
/* rx buffers */
memif_buffer_t *rx_bufs;
/* allcoated rx buffers counter */
/* number of rx buffers pointing to shared memory */
uint16_t rx_buf_num;
memif_packet_handler_t *packet_handler;
/* interface ip address */
uint8_t ip_addr[4];
/* interface hw address */
uint8_t hw_addr[6];
} memif_connection_t;
void print_version ();
int parse_ip4 (const char *input, uint8_t out[4]);
int parse_mac (const char *input, uint8_t out[6]);
void alloc_memif_buffers (memif_connection_t *c);
void free_memif_buffers (memif_connection_t *c);
void print_memif_details (memif_connection_t *c);
void print_memif_rx_ring_details (memif_connection_t *c, uint16_t qid);
void print_memif_tx_ring_details (memif_connection_t *c, uint16_t qid);
int send_packets (memif_connection_t *conn, uint16_t qid,
packet_generator_t *gen, uint32_t num_pkts,
uint16_t max_pkt_size);
/* Expect packets smaller than 2048b */
int responder (memif_conn_handle_t conn, void *private_ctx, uint16_t qid);
/* Expect packets smaller than 2048b */
int responder_zero_copy (memif_conn_handle_t conn, void *private_ctx,
uint16_t qid);
/* reply with the same data */
int basic_packet_handler (memif_connection_t *conn);
/* ICMPv4 and ARP handler */
int icmp_packet_handler (memif_connection_t *conn);
#endif /* COMMON_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2017 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#ifndef _ICMP_PROTO_H_
#define _ICMP_PROTO_H_
typedef enum
{
ICMPR_FLOW_MODE_ETH = 0,
ICMPR_FLOW_MODE_IP,
} icmpr_flow_mode_t;
int resolve_packet (void *in_pck, ssize_t in_size, void *out_pck,
uint32_t *out_size, uint8_t ip_addr[4],
uint8_t hw_addr[6]);
/* resolve packet in place */
int resolve_packet_zero_copy (void *pck, uint32_t *size, uint8_t ip_addr[4],
uint8_t hw_addr[6]);
/* resolve packet in place and add eth encap */
int resolve_packet_zero_copy_add_encap (void **pck, uint32_t *size,
uint8_t ip_addr[4]);
int generate_packet (void *pck, uint32_t *size, uint8_t saddr[4],
uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq);
int generate_packet2 (void *pck, uint32_t *size, uint8_t saddr[4],
uint8_t daddr[4], uint8_t hw_daddr[6], uint32_t seq,
icmpr_flow_mode_t);
int print_packet (void *pck);
#endif /* _ICMP_PROTO_H_ */

View File

@ -0,0 +1,65 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <common.h>
#include <icmp_proto.h>
/* reply with the same data */
int
basic_packet_handler (memif_connection_t *c)
{
int i;
memif_buffer_t *dest, *src;
/* in case of zero-copy the tx_buf_num will be zero, so the loop body won't
* execute */
for (i = 0; i < c->tx_buf_num; i++)
{
memcpy (c->tx_bufs[i].data, c->rx_bufs[i].data, c->rx_bufs[i].len);
}
return 0;
}
/* ICMPv4 and ARP handler */
int
icmp_packet_handler (memif_connection_t *c)
{
int i;
memif_buffer_t *dest, *src;
/* if tx_buf_num > 0 we use non-zero-copy mode */
if (c->tx_buf_num > 0)
{
for (i = 0; i < c->tx_buf_num; i++)
{
resolve_packet (c->rx_bufs[i].data, c->rx_bufs[i].len,
c->tx_bufs[i].data, &c->tx_bufs[i].len, c->ip_addr,
c->hw_addr);
}
}
else
{
for (i = 0; i < c->rx_buf_num; i++)
{
resolve_packet_zero_copy (c->rx_bufs[i].data, &c->rx_bufs[i].len,
c->ip_addr, c->hw_addr);
}
}
return 0;
}

View File

@ -0,0 +1,172 @@
#include <common.h>
int
responder (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
{
memif_connection_t *c = (memif_connection_t *) private_ctx;
int err, i;
uint16_t tx;
/* receive packets from the shared memory */
err = memif_rx_burst (conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &c->rx_buf_num);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_rx_burst: %s", memif_strerror (err));
return err;
}
do
{
/* allocate tx buffers */
err = memif_buffer_alloc (conn, qid, c->tx_bufs, c->rx_buf_num,
&c->tx_buf_num, 2048);
/* suppress full ring error MEMIF_ERR_NOBUF_RING */
if (err != MEMIF_ERR_SUCCESS && err != MEMIF_ERR_NOBUF_RING)
{
INFO ("memif_buffer_alloc: %s", memif_strerror (err));
goto error;
}
/* Process the packets */
if (c->packet_handler == NULL)
{
INFO ("Missing packet handler");
goto error;
}
err = c->packet_handler (c);
if (err != 0)
{
INFO ("packet handler error: %d", err);
goto error;
}
/* Done processing packets */
/* refill the queue */
err = memif_refill_queue (conn, qid, c->tx_buf_num, 0);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_refill_queue: %s", memif_strerror (err));
goto error;
}
c->rx_buf_num -= c->tx_buf_num;
err = memif_tx_burst (conn, qid, c->tx_bufs, c->tx_buf_num, &tx);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_tx_burst: %s", memif_strerror (err));
goto error;
}
c->tx_buf_num -= tx;
/* This should never happen */
if (c->tx_buf_num != 0)
{
INFO ("memif_tx_burst failed to send all allocated buffers.");
goto error;
}
}
while (c->rx_buf_num > 0);
return 0;
error:
err = memif_refill_queue (conn, qid, c->rx_buf_num, 0);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_refill_queue: %s", memif_strerror (err));
return err;
}
c->rx_buf_num = 0;
return -1;
}
int
responder_zero_copy (memif_conn_handle_t conn, void *private_ctx, uint16_t qid)
{
memif_connection_t *c = (memif_connection_t *) private_ctx;
int err, i;
uint16_t tx, tx2;
/* receive packets from the shared memory */
err = memif_rx_burst (conn, qid, c->rx_bufs, MAX_MEMIF_BUFS, &c->rx_buf_num);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_rx_burst: %s", memif_strerror (err));
return err;
}
do
{
/* Note that in zero copy memif_buffer_alloc is not part of respond
process,
* instead rx buffers are used directly using memif_buffer_enq_tx.
* /
/* Process the packets */
if (c->packet_handler == NULL)
{
INFO ("Missing packet handler");
goto error;
}
err = c->packet_handler (c);
if (err != 0)
{
INFO ("packet handler error: %d", err);
goto error;
}
/* Done processing packets */
/* Swap rx and tx buffers, swapped tx buffers are considered allocated
* and are ready to be transmitted. Notice that the buffers are swapped
* only in memif driver and locally remain in rx_bufs queue.
*/
err = memif_buffer_enq_tx (conn, qid, c->rx_bufs, c->rx_buf_num, &tx);
/* suppress full ring error MEMIF_ERR_NOBUF_RING */
if (err != MEMIF_ERR_SUCCESS && err != MEMIF_ERR_NOBUF_RING)
{
INFO ("memif_buffer_alloc: %s", memif_strerror (err));
goto error;
}
/* refill the queue */
err = memif_refill_queue (conn, qid, tx, 0);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_refill_queue: %s", memif_strerror (err));
goto error;
}
c->rx_buf_num -= tx;
/* Notice that we send from rx_bufs as the buffers were only swapped
* internally in memif driver */
err = memif_tx_burst (conn, qid, c->rx_bufs, tx, &tx2);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_tx_burst: %s", memif_strerror (err));
goto error;
}
tx -= tx2;
/* This should never happen */
if (tx != 0)
{
INFO ("memif_tx_burst failed to send all allocated buffers.");
goto error;
}
}
while (c->rx_buf_num > 0);
return 0;
error:
err = memif_refill_queue (conn, qid, c->rx_buf_num, 0);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_refill_queue: %s", memif_strerror (err));
return err;
}
c->rx_buf_num = 0;
return -1;
}

View File

@ -0,0 +1,55 @@
#include <common.h>
int
send_packets (memif_connection_t *c, uint16_t qid,
packet_generator_t *generator, uint32_t num_pkts,
uint16_t max_pkt_size)
{
int err, i;
uint16_t tx;
do
{
err = memif_buffer_alloc (c->conn, qid, c->tx_bufs,
num_pkts > MAX_MEMIF_BUFS ? MAX_MEMIF_BUFS :
num_pkts,
&c->tx_buf_num, max_pkt_size);
/* suppress full ring error MEMIF_ERR_NOBUF_RING */
if (err != MEMIF_ERR_SUCCESS && err != MEMIF_ERR_NOBUF_RING)
{
INFO ("memif_buffer_alloc: %s", memif_strerror (err));
goto error;
}
/* generate packet inside allocated buffers */
err = generator (c, num_pkts);
if (err != 0)
{
INFO ("paclet generator error: %d", err);
goto error;
}
err = memif_tx_burst (c->conn, qid, c->tx_bufs, c->tx_buf_num, &tx);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_tx_burst: %s", memif_strerror (err));
goto error;
}
c->tx_buf_num -= tx;
/* Should never happen... */
if (c->tx_buf_num > 0)
{
INFO ("Failed to send allocated packets");
goto error;
}
num_pkts -= tx;
}
while (num_pkts > 0);
return 0;
error:
/* TODO: free alloocated tx buffers */
return -1;
}

View File

@ -1,248 +0,0 @@
.. _libmemif_example_setup_doc:
Example setup
=============
VPP-memif master icmp_responder slave
-------------------------------------
Libmemif example app(s) use memif default socket file:
``/run/vpp/memif.sock``.
Run VPP and icmpr-epoll example (default example when running in
container).
Other examples work similar to icmpr-epoll. Brief explanation can be
found in :ref:`libmemif_examples_doc` .
VPP-side config:
::
DBGvpp# create interface memif id 0 master
DBGvpp# set int state memif0/0 up
DBGvpp# set int ip address memif0/0 192.168.1.1/24
icmpr-epoll:
::
conn 0 0
Memif in slave mode will try to connect every 2 seconds. If connection
establishment is successful, a message will show.
::
INFO: memif connected!
..
Error messages like “unmatched interface id” are printed only in
debug mode.
Check connected status. Use show command in icmpr-epoll:
::
show
MEMIF DETAILS
==============================
interface index: 0
interface ip: 192.168.1.2
interface name: memif_connection
app name: ICMP_Responder
remote interface name: memif0/0
remote app name: VPP 17.10-rc0~132-g62f9cdd
id: 0
secret:
role: slave
mode: ethernet
socket filename: /run/vpp/memif.sock
rx queues:
queue id: 0
ring size: 1024
buffer size: 2048
tx queues:
queue id: 0
ring size: 1024
buffer size: 2048
link: up
interface index: 1
no connection
Use sh memif command in VPP:
::
DBGvpp# sh memif
interface memif0/0
remote-name "ICMP_Responder"
remote-interface "memif_connection"
id 0 mode ethernet file /run/vpp/memif.sock
flags admin-up connected
listener-fd 12 conn-fd 13
num-s2m-rings 1 num-m2s-rings 1 buffer-size 0
master-to-slave ring 0:
region 0 offset 32896 ring-size 1024 int-fd 16
head 0 tail 0 flags 0x0000 interrupts 0
master-to-slave ring 0:
region 0 offset 0 ring-size 1024 int-fd 15
head 0 tail 0 flags 0x0001 interrupts 0
Send ping from VPP to icmpr-epoll:
::
DBGvpp# ping 192.168.1.2
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=.1888 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=.1985 ms
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=.1813 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=.1929 ms
Statistics: 5 sent, 4 received, 20% packet loss
multiple queues VPP-memif slave icmp_responder master
-----------------------------------------------------
Run icmpr-epoll as in previous example setup. Run VPP with startup conf,
enabling 2 worker threads. Example startup.conf:
::
unix {
interactive
nodaemon
full-coredump
}
cpu {
workers 2
}
VPP-side config:
::
DBGvpp# create memif id 0 slave rx-queues 2 tx-queues 2
DBGvpp# set int state memif0/0 up
DBGvpp# set int ip address memif0/0 192.168.1.1/24
icmpr-epoll:
::
conn 0 1
When connection is established a message will print:
::
INFO: memif connected!
..
Error messages like “unmatched interface id” are printed only in
debug mode.
Check connected status. Use show command in icmpr-epoll:
::
show
MEMIF DETAILS
==============================
interface index: 0
interface ip: 192.168.1.2
interface name: memif_connection
app name: ICMP_Responder
remote interface name: memif0/0
remote app name: VPP 17.10-rc0~132-g62f9cdd
id: 0
secret:
role: master
mode: ethernet
socket filename: /run/vpp/memif.sock
rx queues:
queue id: 0
ring size: 1024
buffer size: 2048
queue id: 1
ring size: 1024
buffer size: 2048
tx queues:
queue id: 0
ring size: 1024
buffer size: 2048
queue id: 1
ring size: 1024
buffer size: 2048
link: up
interface index: 1
no connection
Use sh memif command in VPP:
::
DBGvpp# sh memif
interface memif0/0
remote-name "ICMP_Responder"
remote-interface "memif_connection"
id 0 mode ethernet file /run/vpp/memif.sock
flags admin-up slave connected
listener-fd -1 conn-fd 12
num-s2m-rings 2 num-m2s-rings 2 buffer-size 2048
slave-to-master ring 0:
region 0 offset 0 ring-size 1024 int-fd 14
head 0 tail 0 flags 0x0000 interrupts 0
slave-to-master ring 1:
region 0 offset 32896 ring-size 1024 int-fd 15
head 0 tail 0 flags 0x0000 interrupts 0
slave-to-master ring 0:
region 0 offset 65792 ring-size 1024 int-fd 16
head 0 tail 0 flags 0x0001 interrupts 0
slave-to-master ring 1:
region 0 offset 98688 ring-size 1024 int-fd 17
head 0 tail 0 flags 0x0001 interrupts 0
Send ping from VPP to icmpr-epoll:
::
DBGvpp# ping 192.168.1.2
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=.1439 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=.2184 ms
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=.1458 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=.1687 ms
Statistics: 5 sent, 4 received, 20% packet loss
icmp_responder master icmp_responder slave
------------------------------------------
This setup creates connection between two applications using
libmemif. Traffic functionality is the same as when connection to
VPP. App can receive ARP/ICMP request and transmit response.
Run two instances of icmpr-epoll example. > If not running in container,
make sure folder /run/vpp/ exists before creating memif master. Instance
1 will be in master mode, instance 2 in slave mode. instance 1:
::
conn 0 1
instance 2:
::
conn 0 0
In 2 seconds, both instances should print connected! message:
::
INFO: memif connected!
Check peer interface names using show command.

View File

@ -1,42 +1,87 @@
.. _libmemif_examples_doc:
Examples
========
Libmemif Examples
=================
After build, root folder will contain scripts linking binary examples
with library (same name as example apps). These scripts can be executed
to run example apps without installing the library. Example apps
binaries can be found in *libs* folder. To run binaries directly, make
sure that libmemif library is installed.
Example source code is located in `.../vpp/extras/libmemif/examples/` directory.
The compiled binaries are located in `.../vpp/extras/libmemif/build/examples/`.
Run in container
----------------
``ligato/libmemif-sample-service`` image contains built and installed
libmemf. To run different examples, override docker CMD to start
container in bash:
ICMP Responder
--------------
**Application Source Code**: `.../vpp/extras/libmemif/examples/icmp_responder`
::
In this example, memif endpoint connects to an external application. The example
application can resolve ARP and reply to ICMPv4 packets. The program will exit
once the interface is disconnected Memif receive mode: interrupt.
# docker run -it --entrypoint=/bin/bash -i --rm --name icmp-responder --hostname icmp-responder --privileged -v "/run/vpp/:/run/vpp/" ligato/libmemif-sample-service
VPP (memif master) <--> icmp_responder app (memif slave)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Start VPP and configure memif interface::
Current WORKDIR is set to root repository directory. Example apps can be
run from this directory (a script linking binary with library), or
browse to ``./.libs`` folder and execute binary directly.
make run
...
DBGvpp# create interface memif id 0 master
DBGvpp# set int state memif0/0 up
DBGvpp# set int ip address memif0/0 192.168.1.2/24
* ``extras/libmemif/examples/icmp_responder``
Start icmp_responder example app::
Simplest implementation. Event polling is handled by libmemif.
Single memif connection in slave mode is created (id 0). Use Ctrl + C to exit app.
Memif receive mode: interrupt.
./examples/icmp_responder
* ``extras/libmemif/examples/icmp_responder-epoll`` (run in container by default)
Memif in slave mode will try to connect every 2 seconds. If connection
establishment is successful, the `memif connected` message will show::
Supports multiple connections and master mode. User can create/delete connections, set ip addresses,
print connection information. :ref:`libmemif_example_setup_doc` contains instructions on basic
connection use cases setups. Memif receive mode: interrupt. App provides functionality to disable
interrupts for specified queue/s for testing purposes. Polling mode is not implemented in this example.
INFO: memif connected!
* ``extras/libmemif/examples/icmp_responder-mt``
**Note**: Error messages like "unmatched interface id" are printed only in debug mode.
Multi-thread example, very similar to icmpr-epoll. Packets are handled in threads assigned to specific queues. Slave mode only. Memif receive mode: polling (memif_rx_poll function), interrupt (memif_rx_interrupt function). Receive modes differ per queue.
Verify that the memif is connected on VPP side::
DBGvpp# sh memif
interface memif0/0
remote-name "ICMP_Responder"
remote-interface "memif_connection"
id 0 mode ethernet file /run/vpp/memif.sock
flags admin-up connected
listener-fd 12 conn-fd 13
num-s2m-rings 1 num-m2s-rings 1 buffer-size 0
master-to-slave ring 0:
region 0 offset 32896 ring-size 1024 int-fd 16
head 0 tail 0 flags 0x0000 interrupts 0
master-to-slave ring 0:
region 0 offset 0 ring-size 1024 int-fd 15
head 0 tail 0 flags 0x0001 interrupts 0
Send ping from VPP to icmp_responder (Default IPv4: 192.168.1.1)::
DBGvpp# ping 192.168.1.1
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=.1888 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=.1985 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=.1813 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=.1929 ms
Statistics: 5 sent, 4 received, 20% packet loss
Loopback
--------
**Application Source Code**: `.../vpp/extras/libmemif/examples/loopback`
In this example, two memif endpoints are connected to create a loopback.
Once connected, a test packet is sent out the memif master interface to
the memif slave interface, which replies with the same packet in a
zero-copy way.
In reverse mode, the packet is sent from the slave interface and is
looped back by the master interface.
Running The Loopback Application
++++++++++++++++++++++++++++++++
Start the loopback example::
./examples/loopback
You should see the `Received correct data.` message::
INFO: Received correct data.
INFO: Stopping the program

View File

@ -0,0 +1,241 @@
/*
*------------------------------------------------------------------
* Copyright (c) 2020 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*------------------------------------------------------------------
*/
#include <stdlib.h>
#include <sys/types.h>
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#include <libmemif.h>
#include <common.h>
#define APP_NAME "icmp_responder_example"
#define IF_NAME "libmemif0"
#define IF_ID 0
#define SOCKET_PATH "/run/vpp/memif.sock"
const uint8_t HW_ADDR[6] = { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
const uint8_t IP_ADDR[4] = { 192, 168, 1, 1 };
memif_connection_t intf;
int epfd;
/* informs user about connected status. private_ctx is used by user to identify
* connection */
int
on_connect (memif_conn_handle_t conn, void *private_ctx)
{
INFO ("memif connected!");
int err;
memif_connection_t *c = (memif_connection_t *) private_ctx;
c->is_connected = 1;
alloc_memif_buffers (c);
err = memif_refill_queue (conn, 0, -1, 0);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_refill_queue: %s", memif_strerror (err));
return err;
}
return 0;
}
/* informs user about disconnected status. private_ctx is used by user to
* identify connection */
int
on_disconnect (memif_conn_handle_t conn, void *private_ctx)
{
INFO ("memif disconnected!");
memif_connection_t *c = (memif_connection_t *) private_ctx;
c->is_connected = 0;
free_memif_buffers (c);
/* stop event polling thread */
int err = memif_cancel_poll_event (memif_get_socket_handle (conn));
if (err != MEMIF_ERR_SUCCESS)
INFO ("We are doomed...");
return 0;
}
void
print_help ()
{
printf ("LIBMEMIF EXAMPLE APP: %s", APP_NAME);
#ifdef ICMP_DBG
printf (" (debug)");
#endif
printf ("\n");
printf ("==============================\n");
print_version ();
printf ("==============================\n");
printf (
"In this example, memif endpoint connects to an external application.\n");
printf (
"The example application can resolve ARP and reply to ICMPv4 packets.\n");
printf ("The program will exit once the interface is disconnected.\n");
printf ("==============================\n");
printf ("Usage: icmp_responder [OPTIONS]\n\n");
printf ("Options:\n");
printf ("\t-r\tInterface role <slave|master>. Default: slave\n");
printf ("\t-s\tSocket path. Supports abstract socket using @ before the "
"path. Default: /run/vpp/memif.sock\n");
printf ("\t-i\tInterface id. Default: 0\n");
printf ("\t-a\tIPv4 address. Default: 192.168.1.1\n");
printf ("\t-h\tMac address. Default: aa:aa:aa:aa:aa:aa\n");
printf ("\t-?\tShow help and exit.\n");
printf ("\t-v\tShow libmemif and memif version information and exit.\n");
}
int
main (int argc, char *argv[])
{
memif_socket_args_t memif_socket_args = { 0 };
memif_socket_handle_t memif_socket;
memif_conn_args_t memif_conn_args = { 0 };
int opt, err, ret = 0;
uint8_t is_master = 0;
char socket_path[108];
int id = IF_ID;
strncpy (socket_path, SOCKET_PATH, strlen (SOCKET_PATH));
/* prepare the private data */
memset (&intf, 0, sizeof (intf));
intf.packet_handler = icmp_packet_handler;
memcpy (intf.ip_addr, IP_ADDR, 4);
memcpy (intf.hw_addr, HW_ADDR, 6);
while ((opt = getopt (argc, argv, "r:s:i:a:h:?v")) != -1)
{
switch (opt)
{
case 'r':
if (strncmp (optarg, "master", sizeof (optarg)) == 0)
{
is_master = 1;
}
else if (strncmp (optarg, "slave", sizeof (optarg)) == 0)
{
is_master = 0;
}
else
{
INFO ("Invalid role value: '%s'", optarg);
return -1;
}
break;
case 's':
sprintf (socket_path, "%s", optarg);
break;
case 'i':
id = atoi (optarg);
break;
case 'a':
if (parse_ip4 (optarg, intf.ip_addr) != 0)
{
INFO ("Invalid ipv4 address: %s", optarg);
return -1;
}
break;
case 'h':
if (parse_mac (optarg, intf.hw_addr) != 0)
{
INFO ("Invalid mac address: %s", optarg);
return -1;
}
break;
case '?':
print_help ();
return 0;
case 'v':
print_version ();
return 0;
}
}
/** Create memif socket
*
* Interfaces are internally stored in a database referenced by memif socket.
*/
sprintf (memif_socket_args.path, "%s", socket_path);
/* Set application name */
strncpy (memif_socket_args.app_name, APP_NAME, strlen (APP_NAME));
/* configure autoconnect timer */
if (is_master == 0)
{
memif_socket_args.connection_request_timer.it_value.tv_sec = 2;
memif_socket_args.connection_request_timer.it_value.tv_nsec = 0;
memif_socket_args.connection_request_timer.it_interval.tv_sec = 2;
memif_socket_args.connection_request_timer.it_interval.tv_nsec = 0;
}
err = memif_create_socket (&memif_socket, &memif_socket_args, NULL);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_create_socket: %s", memif_strerror (err));
goto error;
}
/** Create memif interfaces
*
* Both interaces are assigned the same socket and same id to create a
* loopback.
*/
memif_conn_args.socket = memif_socket;
memif_conn_args.interface_id = id;
strncpy (memif_conn_args.interface_name, IF_NAME,
sizeof (memif_conn_args.interface_name));
memif_conn_args.is_master = is_master;
err =
memif_create (&intf.conn, &memif_conn_args, on_connect, on_disconnect,
is_master ? responder : responder_zero_copy, (void *) &intf);
if (err != MEMIF_ERR_SUCCESS)
{
INFO ("memif_create_socket: %s", memif_strerror (err));
return err;
}
do
{
err = memif_poll_event (memif_socket, -1);
}
while (err == MEMIF_ERR_SUCCESS);
return 0;
error:
ret = -1;
done:
free_memif_buffers (&intf);
memif_delete (&intf.conn);
memif_delete_socket (&memif_socket);
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,5 @@ The interface will by default connect to a master interface listening on
``/run/vpp/master.sock``. The example will handle ARP requests and
respond to ICMPv4 requests to ``192.168.1.1``.
Continue with :ref:`libmemif_example_setup_doc` which contains instructions on
how to set up connection between icmpr-epoll example app and VPP-memif.
Continue with :ref:`libmemif_examples_doc` which contains instructions on
how to set up connection between icmp_responder example app and VPP-memif.