diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/README.md | 191 |
1 files changed, 138 insertions, 53 deletions
diff --git a/apps/README.md b/apps/README.md index bee6545a6..eefb68be1 100644 --- a/apps/README.md +++ b/apps/README.md @@ -82,73 +82,110 @@ We consider the following topology, consisting on two linux VM which are able to ``` Install the hICN suite on two linux VM. This tutorial makes use of Ubuntu 18.04, but it could easily be adapted to other platforms. -You can either install the hICN stack using binaries or compile the code. In this tutorial we will build the code from source. +You can either install the hICN stack using binaries or compile the code. In this tutorial we will make use of docker container and binaries packages. -```bash -$ curl -s https://packagecloud.io/install/repositories/fdio/release/script.deb.sh | sudo bash -$ apt-get install -y git \ - cmake \ - build-essential \ - libasio-dev \ - libcurl4-openssl-dev \ - libparc-dev \ - --no-install-recommends +The client will use of the hicn-light forwarder, which is lightweight and tailored for devices such as android and laptops. +The server will use the hicn-plugin of vpp, which guarantees better performances and it is the best choice for server applications. + +Keep in mind that on the same system the stack based on vpp forwarder cannot coexist with the stack based on hicn light. + +For running the hicn-plugin at the server there are two main alternatives: + +- Use a docker container +- Run the hicn-plugin directly in a VM or Bare Metal Server -$ mkdir hicn-suite && cd hicn-suite -$ git clone https://github.com/FDio/hicn hicn-src -$ mkdir hicn-build && cd hicn-build -$ cmake ../hicn-src -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../hicn-install -DBUILD_APPS=ON -$ make -j 4 install -$ export HICN_ROOT=${PWD}/../hicn-install +#### Docker + +Install docker in the server VM: + +```bash +server$ sudo apt-get update +server$ sudo apt-get install \ + apt-transport-https \ + ca-certificates \ + curl \ + gnupg-agent \ + software-properties-common + +server$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - +server$ sudo add-apt-repository \ + "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) \ + stable" +server$ sudo apt-get update +server$ sudo apt-get install docker-ce docker-ce-cli containerd.io ``` -It should install the hICN suite under hicn-install. +Run the hicn-http-proxy container. Here we use a public server [example.com](example.com) as origin: -#### hICN stack based on hicn-light forwarder with UDP faces +```bash +server$ docker run -e ORIGIN_ADDRESS=example.com \ + -e ORIGIN_PORT=80 \ + -e CACHE_SIZE=10000 \ + -e HICN_MTU=1200 \ + -e FIRST_IPV6_WORD=c001 \ + -e HICN_PREFIX=http://webserver \ + --privileged \ + --name vhttpproxy \ + -d icnteam/vhttpproxy +``` -##### Server Configuration +Create a hicn private network: -Open a new terminal on the machine where you want to run the HTTP server and install apache2 http server: +```bash +server$ GATEWAY=192.168.0.254 +server$ docker network create --subnet 192.168.0.0/24 --gateway ${GATEWAY} hicn-network +``` + +Connect the proxy container to the hicn network: ```bash -server$ sudo apt-get install -y apache2 -server$ sudo systemctl start apache2 +server$ docker network connect hicn-network vhttpproxy ``` -Create a configuration file for the hicn-light forwarder. Here we are configuring UDP faces. +Connect the hicn network to the vpp forwarder: ```bash -server$ mkdir -p ${HICN_ROOT}/etc -server$ LOCAL_IP="10.0.0.1" # Put here the actual IPv4 of the local interface -server$ LOCAL_PORT="12345" -server$ cat << EOF > ${HICN_ROOT}/etc/hicn-light.conf -add listener udp list0 ${LOCAL_IP} ${LOCAL_PORT} -EOF +server$ IP_ADDRESS=$(docker inspect -f "{{with index .NetworkSettings.Networks \"hicn-network\"}}{{.IPAddress}}{{end}}" vhttpproxy) +server$ INTERFACE=$(docker exec -it vhttpproxy ifconfig | grep -B 1 ${IP_ADDRESS} | awk 'NR==1 {gsub(":","",$1); print $1}') +server$ docker exec -it vhttpproxy ip addr flush dev ${INTERFACE} +server$ docker exec -it vhttpproxy ethtool -K ${INTERFACE} tx off rx off ufo off gso off gro off tso off +server$ docker exec -it vhttpproxy vppctl create host-interface name ${INTERFACE} +server$ docker exec -it vhttpproxy vppctl set interface state host-${INTERFACE} up +server$ docker exec -it vhttpproxy vppctl set interface ip address host-${INTERFACE} ${IP_ADDRESS}/24 +server$ docker exec -it vhttpproxy vppctl ip route add 10.0.0.0/24 via ${GATEWAY} host-eth1 ``` -Start the hicn-light forwarder +Set the punting: ```bash -server$ sudo ${HICN_ROOT}/bin/hicn-light-daemon --daemon --capacity 1000 --log-file ${HICN_ROOT}/hicn-light.log --config ${HICN_ROOT}/etc/hicn-light.conf +server$ PORT=12345 +server$ docker exec -it vhttpproxy vppctl hicn punting add prefix c001::/16 intfc host-${INTERFACE} type udp4 src_port ${PORT} dst_port ${PORT} ``` -Run the [hicn-http-proxy](#hicn-http-proxy). Assuming the http origin is listening on port 80: +Docker containers are cool, but sometimes they do not allow you to do simple operations like expose ports while the container is already running. But we have a workaround for this :) ```bash -server$ ${HICN_ROOT}/bin/hicn-http-proxy -a 127.0.0.1 -p 80 -c 10000 -m 1200 -P c001 http://webserver +server$ sudo iptables -t nat -A DOCKER -p udp --dport ${PORT} -j DNAT --to-destination ${IP_ADDRESS}:${PORT} +server$ sudo iptables -t nat -A POSTROUTING -j MASQUERADE -p udp --source ${IP_ADDRESS} --destination ${IP_ADDRESS} --dport ${PORT} +server$ sudo iptables -A DOCKER -j ACCEPT -p udp --destination ${IP_ADDRESS} --dport ${PORT} ``` -##### Client Configuration +In the client, install the hicn stack: -Create a configuration file for the hicn-light forwarder. Here we are configuring UDP faces. +```bash +client$ sudo apt-get install -y hicn-light hicn-apps +``` + +Create a configuration file for the hicn-light forwarder. Here we are configuring UDP faces: ```bash -client$ mkdir -p ${HICN_ROOT}/etc +client$ mkdir -p ${HOME}/etc client$ LOCAL_IP="10.0.0.2" # Put here the actual IPv4 of the local interface client$ LOCAL_PORT="12345" client$ REMOTE_IP="10.0.0.1" # Put here the actual IPv4 of the remote interface client$ REMOTE_PORT="12345" -client$ cat << EOF > ${HICN_ROOT}/etc/hicn-light.conf +client$ cat << EOF > ${HOME}/etc/hicn-light.conf add listener udp list0 ${LOCAL_IP} ${LOCAL_PORT} add connection udp conn0 ${REMOTE_IP} ${REMOTE_PORT} ${LOCAL_IP} ${LOCAL_PORT} add route conn0 c001::/16 1 @@ -158,39 +195,74 @@ EOF Run the hicn-light forwarder ```bash -client$ sudo ${HICN_ROOT}/bin/hicn-light-daemon --daemon --capacity 1000 --log-file ${HICN_ROOT}/hicn-light.log --config ${HICN_ROOT}/etc/hicn-light.conf +client$ sudo /usr/bin/hicn-light-daemon --daemon --capacity 1000 --log-file ${HOME}/hicn-light.log --config ${HOME}/etc/hicn-light.conf ``` Run the http client [higet](#higet) and print the http response on stdout: ```bash -client$ ${HICN_ROOT}/bin/higet -O - http://webserver/index.html -P c001 -EOF +client$ /usr/bin/higet -O - http://webserver/index.html -P c001 ``` -#### Using hicn-light forwarder with hICN faces +#### Host/VM -For sending hICN packets directly over the network, using hicn faces, change the configuration of the two forwarders and restart them. +You can install the hicn-plugin of vpp on your VM and directly use DPDK compatible nics, forwarding hicn packets directly over the network. DPDK compatible nics can be used inside a container as well. + +```bash +server$ sudo apt-get install -y hicn-plugin vpp-plugin-dpdk hicn-apps-memif +``` -##### Server Configuration +It will install all the required deps (vpp, hicn apps and libraries compiled for communicating with vpp using shared memories). Configure VPP following the steps described [here](https://github.com/FDio/hicn/blob/master/hicn-plugin/README.md#configure-vpp). + +This tutorial assumes you configured two interfaces in your server VM: + +- One interface which uses the DPDK driver, to be used by VPP +- One interface which is still owned by the kernel + +The DPDK interface will be used for connecting the server with the hicn client, while the other interface will guarantee connectivity to the applications running in the VM, including the hicn-http-proxy. If you run the commands: ```bash -server$ mkdir -p ${HICN_ROOT}/etc -server$ LOCAL_IP="9001::1" -server$ cat << EOF > ${HICN_ROOT}/etc/hicn-light.conf -add listener hicn lst 0::0 -add punting lst c001::/16 -add listener hicn list0 ${LOCAL_IP} -EOF +server$ sudo systemctl restart vpp +server$ vppctl show int +``` + +The output must show the dpdk interface owned by VPP: + +```text + Name Idx State MTU (L3/IP4/IP6/MPLS) Counter Count +GigabitEthernetb/0/0 1 down 9000/0/0/0 /*
* Copyright (c) 2015 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 "vat.h"
#include "plugin.h"
#include <signal.h>
vat_main_t vat_main;
#include <vlibapi/api_helper_macros.h>
void
vat_suspend (vlib_main_t * vm, f64 interval)
{
/* do nothing in the standalone version, just return */
}
int
connect_to_vpe (char *name)
{
vat_main_t *vam = &vat_main;
api_main_t *am = &api_main;
if (vl_client_connect_to_vlib ("/vpe-api", name, 32) < 0)
return -1;
vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
vam->my_client_index = am->my_client_index;
return 0;
}
vlib_main_t vlib_global_main;
vlib_main_t **vlib_mains;
void
vlib_cli_output (struct vlib_main_t *vm, char *fmt, ...)
{
clib_warning ("BUG");
}
static u8 *
format_api_error (u8 * s, va_list * args)
{
vat_main_t *vam = va_arg (*args, vat_main_t *);
i32 error = va_arg (*args, u32);
uword *p;
p = hash_get (vam->error_string_by_error_number, -error);
if (p)
s = format (s, "%s", p[0]);
else
s = format (s, "%d", error);
return s;
}
void
do_one_file (vat_main_t * vam)
{
int rv;
int (*fp) (vat_main_t * vam);
int arg_len;
unformat_input_t _input;
u8 *cmdp, *argsp;
uword *p;
u8 *this_cmd = 0;
vam->input = &_input;
/* Used by the "quit" command handler */
if (setjmp (vam->jump_buf) != 0)
return;
vam->jump_buf_set = 1;
while (1)
{
if (vam->ifp == stdin)
{
if (vam->exec_mode == 0)
rv = write (1, "vat# ", 5);
else
rv = write (1, "exec# ", 6);
}
_vec_len (vam->inbuf) = 4096;
if (vam->do_exit ||
fgets ((char *) vam->inbuf, vec_len (vam->inbuf), vam->ifp) == 0)
break;
vam->input_line_number++;
vec_free (this_cmd);
this_cmd =
(u8 *) clib_macro_eval (&vam->macro_main, (i8 *) vam->inbuf,
1 /* complain */ );
if (vam->exec_mode == 0)
{
/* Split input into cmd + args */
cmdp = this_cmd;
while (cmdp < (this_cmd + vec_len (this_cmd)))
{
if (*cmdp == ' ' || *cmdp == '\t' || *cmdp == '\n')
{
cmdp++;
}
else
break;
}
argsp = cmdp;
while (argsp < (this_cmd + vec_len (this_cmd)))
{
if (*argsp != ' ' && *argsp != '\t' && *argsp != '\n')
{
argsp++;
}
else
break;
}
*argsp++ = 0;
while (argsp < (this_cmd + vec_len (this_cmd)))
{
if (*argsp == ' ' || *argsp == '\t' || *argsp == '\n')
{
argsp++;
}
else
break;
}
/* Blank input line? */
if (*cmdp == 0)
continue;
p = hash_get_mem (vam->function_by_name, cmdp);
if (p == 0)
{
errmsg ("'%s': function not found\n", cmdp);
continue;
}
arg_len = strlen ((char *) argsp);
unformat_init_string (vam->input, (char *) argsp, arg_len);
fp = (void *) p[0];
}
else
{
unformat_init_string (vam->input, (char *) this_cmd,
strlen ((char *) this_cmd));
cmdp = this_cmd;
fp = exec;
}
rv = (*fp) (vam);
if (rv < 0)
errmsg ("%s error: %U\n", cmdp, format_api_error, vam, rv);
unformat_free (vam->input);
if (vam->regenerate_interface_table)
{
vam->regenerate_interface_table = 0;
api_sw_interface_dump (vam);
}
/* Hack to pick up new client index after memfd_segment_create pivot */
if (vam->client_index_invalid)
{
vat_main_t *vam = &vat_main;
api_main_t *am = &api_main;
vam->vl_input_queue = am->shmem_hdr->vl_input_queue;
vam->my_client_index = am->my_client_index;
vam->client_index_invalid = 0;
}
}
}
static void
init_error_string_table (vat_main_t * vam)
{
vam->error_string_by_error_number = hash_create (0, sizeof (uword));
#define _(n,v,s) hash_set (vam->error_string_by_error_number, -v, s);
foreach_vnet_api_error;
#undef _
hash_set (vam->error_string_by_error_number, 99, "Misc");
}
static i8 *
eval_current_file (macro_main_t * mm, i32 complain)
{
vat_main_t *vam = &vat_main;
return ((i8 *) format (0, "%s%c", vam->current_file, 0));
}
static i8 *
eval_current_line (macro_main_t * mm, i32 complain)
{
vat_main_t *vam = &vat_main;
return ((i8 *) format (0, "%d%c", vam->input_line_number, 0));
}
static void
signal_handler (int signum, siginfo_t * si, ucontext_t * uc)
{
vat_main_t *vam = &vat_main;
switch (signum)
{
/* these (caught) signals cause the application to exit */
case SIGINT:
case SIGTERM:
if (vam->jump_buf_set)
{
vam->do_exit = 1;
return;
}
/* FALLTHROUGH on purpose */
default:
break;
}
_exit (1);
}
static void
setup_signal_handlers (void)
{
uword i;
struct sigaction sa;
for (i = 1; i < 32; i++)
{
memset (&sa, 0, sizeof (sa));
sa.sa_sigaction = (void *) signal_handler;
sa.sa_flags = SA_SIGINFO;
switch (i)
{
/* these signals take the default action */
case SIGABRT:
case SIGKILL:
case SIGSTOP:
case SIGUSR1:
case SIGUSR2:
continue;
/* ignore SIGPIPE, SIGCHLD */
case SIGPIPE:
case SIGCHLD:
sa.sa_sigaction = (void *) SIG_IGN;
break;
/* catch and handle all other signals */
default:
break;
}
if (sigaction (i, &sa, 0) < 0)
clib_unix_warning ("sigaction %U", format_signal, i);
}
}
int
main (int argc, char **argv)
{
vat_main_t *vam = &vat_main;
unformat_input_t _argv, *a = &_argv;
u8 **input_files = 0;
u8 *output_file = 0;
u8 *chroot_prefix;
u8 *this_input_file;
u8 interactive = 1;
u8 json_output = 0;
int i;
f64 timeout;
clib_mem_init_thread_safe (0, 128 << 20);
clib_macro_init (&vam->macro_main);
clib_macro_add_builtin (&vam->macro_main, "current_file",
eval_current_file);
clib_macro_add_builtin (&vam->macro_main, "current_line",
eval_current_line);
init_error_string_table (vam);
vec_validate (vam->cmd_reply, 0);
vec_reset_length (vam->cmd_reply);
unformat_init_command_line (a, argv);
while (unformat_check_input (a) != UNFORMAT_END_OF_INPUT)
{
if (unformat (a, "in %s", &this_input_file))
vec_add1 (input_files, this_input_file);
else if (unformat (a, "out %s", &output_file))
;
else if (unformat (a, "script"))
interactive = 0;
else if (unformat (a, "json"))
json_output = 1;
else if (unformat (a, "socket-name %s", &vam->socket_name))
;
else if (unformat (a, "default-socket"))
{
vam->socket_name = format (0, "%s%c", API_SOCKET_FILE, 0);
}
else if (unformat (a, "plugin_path %s", (u8 *) & vat_plugin_path))
vec_add1 (vat_plugin_path, 0);
else if (unformat (a, "plugin_name_filter %s",
(u8 *) & vat_plugin_name_filter))
vec_add1 (vat_plugin_name_filter, 0);
else if (unformat (a, "chroot prefix %s", &chroot_prefix))
{
vl_set_memory_root_path ((char *) chroot_prefix);
}
else
{
fformat
(stderr,
"%s: usage [in <f1> ... in <fn>] [out <fn>] [script] [json]\n"
"[plugin_path <path>][default-socket][socket-name <name>]\n"
"[plugin_name_filter <filter>][chroot prefix <path>]\n",
argv[0]);
exit (1);
}
}
if (output_file)
vam->ofp = fopen ((char *) output_file, "w");
else
vam->ofp = stdout;
if (vam->ofp == NULL)
{
fformat (stderr, "Couldn't open output file %s\n",
output_file ? (char *) output_file : "stdout");
exit (1);
}
clib_time_init (&vam->clib_time);
vat_api_hookup (vam);
vat_plugin_api_reference ();
setup_signal_handlers ();
if (vam->socket_name && vat_socket_connect (vam))
fformat (stderr, "WARNING: socket connection failed");
if ((!vam->socket_client_main || vam->socket_client_main->socket_fd == 0)
&& connect_to_vpe ("vpp_api_test") < 0)
{
svm_region_exit ();
fformat (stderr, "Couldn't connect to vpe, exiting...\n");
exit (1);
}
vam->json_output = json_output;
if (!json_output)
api_sw_interface_dump (vam);
vec_validate (vam->inbuf, 4096);
vam->current_file = (u8 *) "plugin-init";
vat_plugin_init (vam);
for (i = 0; i < vec_len (input_files); i++)
{
vam->ifp = fopen ((char *) input_files[i], "r");
if (vam->ifp == NULL)
{
fformat (stderr, "Couldn't open input file %s\n", input_files[i]);
continue;
}
vam->current_file = input_files[i];
vam->input_line_number = 0;
do_one_file (vam);
fclose (vam->ifp);
}
if (output_file)
fclose (vam->ofp);
if (interactive)
{
vam->ifp = stdin;
vam->ofp = stdout;
vam->current_file = (u8 *) "interactive";
do_one_file (vam);
fclose (vam->ifp);
}
/*
* Particularly when running a script, don't be in a hurry to leave.
* A reply message queued to this process will end up constipating
* the allocation rings.
*/
timeout = vat_time_now (vam) + 2.0;
while (vam->result_ready == 0 && vat_time_now (vam) < timeout)
;
if (vat_time_now (vam) > timeout)
clib_warning ("BUG: message reply spin-wait timeout");
vl_client_disconnect_from_vlib ();
exit (0);
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/
|