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 $(CONFIRM) $(FORCE) install $$inst; \
|
||||
fi
|
||||
else ifneq ("$(wildcard /etc/redhat-release)","")
|
||||
@sudo yum install $(CONFIRM) $(DOC_RPM_DEPENDS)
|
||||
endif
|
||||
|
||||
.PHONY: spell
|
||||
|
@ -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
|
||||
|
@ -1 +0,0 @@
|
||||
../../../extras/libmemif/examples/example_setup_doc.rst
|
@ -19,6 +19,5 @@ packets using libmemif API.
|
||||
|
||||
libmemif_doc
|
||||
buildinstructions_doc
|
||||
example_setup_doc
|
||||
examples_doc
|
||||
gettingstarted_doc
|
||||
examples_doc
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
|
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:
|
||||
|
||||
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
|
||||
|
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
|
||||
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.
|
||||
|
Reference in New Issue
Block a user