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:

committed by
Damjan Marion

parent
7d6f7d0d67
commit
e74c04fc9f
@ -67,8 +67,6 @@ ifeq ($(OS_ID),ubuntu)
|
|||||||
sudo apt-get update; \
|
sudo apt-get update; \
|
||||||
sudo apt-get $(CONFIRM) $(FORCE) install $$inst; \
|
sudo apt-get $(CONFIRM) $(FORCE) install $$inst; \
|
||||||
fi
|
fi
|
||||||
else ifneq ("$(wildcard /etc/redhat-release)","")
|
|
||||||
@sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: spell
|
.PHONY: spell
|
||||||
|
@ -21,7 +21,7 @@ import subprocess
|
|||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = u'The Vector Packet Processor'
|
project = u'The Vector Packet Processor'
|
||||||
copyright = u'2018-2021, Linux Foundation'
|
copyright = u'2018-2022, Linux Foundation'
|
||||||
author = u'FD.io VPP Community'
|
author = u'FD.io VPP Community'
|
||||||
|
|
||||||
# The short X.Y version
|
# The short X.Y version
|
||||||
|
@ -1 +0,0 @@
|
|||||||
../../../extras/libmemif/examples/example_setup_doc.rst
|
|
@ -19,6 +19,5 @@ packets using libmemif API.
|
|||||||
|
|
||||||
libmemif_doc
|
libmemif_doc
|
||||||
buildinstructions_doc
|
buildinstructions_doc
|
||||||
example_setup_doc
|
|
||||||
examples_doc
|
|
||||||
gettingstarted_doc
|
gettingstarted_doc
|
||||||
|
examples_doc
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
FROM ubuntu:xenial
|
FROM ubuntu:xenial
|
||||||
|
|
||||||
RUN apt-get update && \
|
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 rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN mkdir /libmemif
|
RUN mkdir /libmemif
|
||||||
ADD . /libmemif
|
ADD . /libmemif
|
||||||
WORKDIR /libmemif
|
WORKDIR /libmemif
|
||||||
|
|
||||||
RUN ./bootstrap
|
RUN mkdir build
|
||||||
RUN ./configure
|
RUN cmake ..
|
||||||
|
WORKDIR /libmemif/build
|
||||||
RUN make
|
RUN make
|
||||||
RUN make install
|
|
||||||
|
|
||||||
RUN mkdir /run/vpp
|
RUN mkdir /run/vpp
|
||||||
|
|
||||||
RUN ulimit -c unlimited
|
RUN ulimit -c unlimited
|
||||||
|
|
||||||
CMD ./.libs/icmpr-epoll
|
CMD ./examples/icmp_responder
|
||||||
|
@ -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
|
Libmemif is now part of VPP repository. Follow fd.io wiki to pull source
|
||||||
code from VPP repository.
|
code from VPP repository.
|
||||||
https://wiki.fd.io/view/VPP/Pulling,_Building,_Running,_Hacking_and_Pushing_VPP_Code#Pushing_Patches
|
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 -p extras/libmemif/build
|
||||||
|
cd extras/libmemif/build
|
||||||
# mkdir build
|
cmake ..
|
||||||
# cd build
|
make install
|
||||||
# cmake ..
|
|
||||||
# make install
|
|
||||||
|
|
||||||
Verify installation:
|
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
|
Options:
|
||||||
==============================
|
-r Interface role <slave|master>. Default: slave
|
||||||
libmemif version: 4.0, memif version: 2.0
|
-s Socket path. Supports abstract socket using @ before the path. Default: /run/vpp/memif.sock
|
||||||
==============================
|
-i Interface id. Default: 0
|
||||||
In this example, memif endpoint connects to an external application.
|
-a IPv4 address. Default: 192.168.1.1
|
||||||
The example application can resolve ARP and reply to ICMPv4 packets.
|
-h Mac address. Default: aa:aa:aa:aa:aa:aa
|
||||||
The program will exit once the interface is disconnected.
|
-? Show help and exit.
|
||||||
==============================
|
-v Show libmemif and memif version information and exit.
|
||||||
Usage: icmp_responder [OPTIONS]
|
|
||||||
|
|
||||||
Options:
|
Use Cases
|
||||||
-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.
|
|
||||||
|
|
||||||
Examples
|
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.
|
||||||
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.
|
|
||||||
|
@ -13,20 +13,25 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
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
|
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
|
list(APPEND EXAMPLES_LIST
|
||||||
|
loopback/main.c
|
||||||
|
icmp_responder/main.c
|
||||||
)
|
)
|
||||||
|
|
||||||
foreach (EXAMPLE_SRC ${EXAMPLES_LIST})
|
foreach (EXAMPLE_SRC ${EXAMPLES_LIST})
|
||||||
string(FIND ${EXAMPLE_SRC} "/" INDEX)
|
string(FIND ${EXAMPLE_SRC} "/" INDEX)
|
||||||
string(SUBSTRING ${EXAMPLE_SRC} 0 ${INDEX} EXECUTABLE)
|
string(SUBSTRING ${EXAMPLE_SRC} 0 ${INDEX} EXECUTABLE)
|
||||||
add_executable(${EXECUTABLE} ${COMMON_SOURCE_FILES} ${EXAMPLE_SRC})
|
add_executable(${EXECUTABLE} ${COMMON_SOURCE_FILES} ${EXAMPLE_SRC} )
|
||||||
target_include_directories(${EXECUTABLE} PRIVATE $<BUILD_INTERFACE:${HEADERS_DIR}>)
|
target_include_directories(${EXECUTABLE} PRIVATE $<BUILD_INTERFACE:${COMMON_HEADERS}>)
|
||||||
target_link_libraries(${EXECUTABLE} memif ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(${EXECUTABLE} memif ${CMAKE_THREAD_LIBS_INIT})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
192
extras/libmemif/examples/common/common.c
Normal file
192
extras/libmemif/examples/common/common.c
Normal 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);
|
||||||
|
}
|
116
extras/libmemif/examples/common/common.h
Normal file
116
extras/libmemif/examples/common/common.h
Normal 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 */
|
520
extras/libmemif/examples/common/icmp_proto.c
Normal file
520
extras/libmemif/examples/common/icmp_proto.c
Normal file
File diff suppressed because it is too large
Load Diff
48
extras/libmemif/examples/common/icmp_proto.h
Normal file
48
extras/libmemif/examples/common/icmp_proto.h
Normal 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_ */
|
65
extras/libmemif/examples/common/packet_handler.c
Normal file
65
extras/libmemif/examples/common/packet_handler.c
Normal 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;
|
||||||
|
}
|
172
extras/libmemif/examples/common/responder.c
Normal file
172
extras/libmemif/examples/common/responder.c
Normal 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;
|
||||||
|
}
|
55
extras/libmemif/examples/common/sender.c
Normal file
55
extras/libmemif/examples/common/sender.c
Normal 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;
|
||||||
|
}
|
@ -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.
|
|
@ -1,42 +1,87 @@
|
|||||||
.. _libmemif_examples_doc:
|
.. _libmemif_examples_doc:
|
||||||
|
|
||||||
Examples
|
Libmemif Examples
|
||||||
========
|
=================
|
||||||
|
|
||||||
After build, root folder will contain scripts linking binary examples
|
Example source code is located in `.../vpp/extras/libmemif/examples/` directory.
|
||||||
with library (same name as example apps). These scripts can be executed
|
The compiled binaries are located in `.../vpp/extras/libmemif/build/examples/`.
|
||||||
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.
|
|
||||||
|
|
||||||
Run in container
|
|
||||||
----------------
|
|
||||||
|
|
||||||
``ligato/libmemif-sample-service`` image contains built and installed
|
ICMP Responder
|
||||||
libmemf. To run different examples, override docker CMD to start
|
--------------
|
||||||
container in bash:
|
**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
|
make run
|
||||||
run from this directory (a script linking binary with library), or
|
...
|
||||||
browse to ``./.libs`` folder and execute binary directly.
|
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.
|
./examples/icmp_responder
|
||||||
Single memif connection in slave mode is created (id 0). Use Ctrl + C to exit app.
|
|
||||||
Memif receive mode: interrupt.
|
|
||||||
|
|
||||||
* ``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,
|
INFO: memif connected!
|
||||||
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.
|
|
||||||
|
|
||||||
* ``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
|
||||||
|
241
extras/libmemif/examples/icmp_responder/main.c
Normal file
241
extras/libmemif/examples/icmp_responder/main.c
Normal 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;
|
||||||
|
}
|
307
extras/libmemif/examples/loopback/main.c
Normal file
307
extras/libmemif/examples/loopback/main.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
``/run/vpp/master.sock``. The example will handle ARP requests and
|
||||||
respond to ICMPv4 requests to ``192.168.1.1``.
|
respond to ICMPv4 requests to ``192.168.1.1``.
|
||||||
|
|
||||||
Continue with :ref:`libmemif_example_setup_doc` which contains instructions on
|
Continue with :ref:`libmemif_examples_doc` which contains instructions on
|
||||||
how to set up connection between icmpr-epoll example app and VPP-memif.
|
how to set up connection between icmp_responder example app and VPP-memif.
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user