summaryrefslogtreecommitdiffstats
path: root/hicn-plugin/src/host_stack
diff options
context:
space:
mode:
Diffstat (limited to 'hicn-plugin/src/host_stack')
-rw-r--r--hicn-plugin/src/host_stack/FEATURE.yaml9
-rw-r--r--hicn-plugin/src/host_stack/README.md2
-rw-r--r--hicn-plugin/src/host_stack/cbr_proto.c101
-rw-r--r--hicn-plugin/src/host_stack/cli.c99
-rw-r--r--hicn-plugin/src/host_stack/debug.h0
-rw-r--r--hicn-plugin/src/host_stack/error.c32
-rw-r--r--hicn-plugin/src/host_stack/error.h33
-rw-r--r--hicn-plugin/src/host_stack/errors/hicn_hs.def32
-rw-r--r--hicn-plugin/src/host_stack/host_stack.c517
-rw-r--r--hicn-plugin/src/host_stack/host_stack.h406
-rw-r--r--hicn-plugin/src/host_stack/inlines.h520
-rw-r--r--hicn-plugin/src/host_stack/input_node.c477
-rw-r--r--hicn-plugin/src/host_stack/output_node.c287
-rw-r--r--hicn-plugin/src/host_stack/producer_dpo.c90
-rw-r--r--hicn-plugin/src/host_stack/producer_dpo.h33
-rw-r--r--hicn-plugin/src/host_stack/proto.h48
-rw-r--r--hicn-plugin/src/host_stack/route.c178
-rw-r--r--hicn-plugin/src/host_stack/route.h37
-rw-r--r--hicn-plugin/src/host_stack/test/hicn_hs_client.c804
-rw-r--r--hicn-plugin/src/host_stack/test/hicn_hs_client.h127
-rw-r--r--hicn-plugin/src/host_stack/test/hicn_hs_server.c505
-rw-r--r--hicn-plugin/src/host_stack/testbed/Dockerfile46
-rw-r--r--hicn-plugin/src/host_stack/testbed/client-startup.txt6
-rw-r--r--hicn-plugin/src/host_stack/testbed/init.sh6
-rw-r--r--hicn-plugin/src/host_stack/testbed/run-client-server.sh24
-rw-r--r--hicn-plugin/src/host_stack/testbed/server-startup.txt7
-rw-r--r--hicn-plugin/src/host_stack/testbed/startup-client.conf188
-rw-r--r--hicn-plugin/src/host_stack/testbed/startup-server.conf189
-rw-r--r--hicn-plugin/src/host_stack/testbed/test_hicn_hs.txt6
-rw-r--r--hicn-plugin/src/host_stack/testbed/vcl.conf7
-rw-r--r--hicn-plugin/src/host_stack/utils.h95
31 files changed, 4911 insertions, 0 deletions
diff --git a/hicn-plugin/src/host_stack/FEATURE.yaml b/hicn-plugin/src/host_stack/FEATURE.yaml
new file mode 100644
index 000000000..580af2723
--- /dev/null
+++ b/hicn-plugin/src/host_stack/FEATURE.yaml
@@ -0,0 +1,9 @@
+---
+name: Hicn host stack
+maintainer: Mauro Sardara <msardara@cisco.com>
+features:
+ - Hicn host stack integration via session layer
+description: "IETF QUIC Protocol implementation"
+state: experimental
+properties: [API, CLI, STATS, MULTITHREAD]
+
diff --git a/hicn-plugin/src/host_stack/README.md b/hicn-plugin/src/host_stack/README.md
new file mode 100644
index 000000000..04166336a
--- /dev/null
+++ b/hicn-plugin/src/host_stack/README.md
@@ -0,0 +1,2 @@
+# host-stack-plugin
+HICN transport plugin for VPP
diff --git a/hicn-plugin/src/host_stack/cbr_proto.c b/hicn-plugin/src/host_stack/cbr_proto.c
new file mode 100644
index 000000000..54a851d41
--- /dev/null
+++ b/hicn-plugin/src/host_stack/cbr_proto.c
@@ -0,0 +1,101 @@
+/*
+ * 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 "host_stack.h"
+#include "inlines.h"
+
+#include <hicn/transport/protocols/transport_algorithm.h>
+
+#define WINDOW_SIZE 200
+
+typedef struct hicn_hs_cbr_proto_data_
+{
+ u64 next_seq_number;
+ u16 window_size;
+ u16 in_flight_interests;
+} hicn_hs_cbr_proto_data_t;
+
+#define proto_data(ctx) ((hicn_hs_cbr_proto_data_t *)(ctx->hs_proto_data))
+
+static void
+reset_protocol(hicn_hs_cbr_proto_data_t *proto_data)
+{
+ proto_data->in_flight_interests = 0;
+ proto_data->window_size = WINDOW_SIZE;
+ proto_data->next_seq_number = 0;
+
+ TransportAlgorithm *t = transportAlgorithm_CreateRaaqm(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ proto_data->next_seq_number = (u64)t;
+}
+
+static void
+schedule_next_interests(hicn_hs_ctx_t *ctx)
+{
+ hicn_hs_cbr_proto_data_t *data = proto_data(ctx);
+ u32 scheduled_interests = 0;
+
+ if (data->in_flight_interests < data->window_size)
+ scheduled_interests = hicn_hs_send_interests(ctx, data->next_seq_number,
+ data->window_size - data->in_flight_interests);
+
+ data->in_flight_interests += scheduled_interests;
+ data->next_seq_number += scheduled_interests;
+}
+
+u32 cbr_proto_init(hicn_hs_ctx_t *ctx)
+{
+ if (ctx->running)
+ return -1;
+
+ hicn_hs_cbr_proto_data_t *data = proto_data(ctx);
+
+ reset_protocol(data);
+ schedule_next_interests(ctx);
+ ctx->running = 1;
+
+ return 0;
+}
+
+u32 cbr_proto_on_data(hicn_hs_ctx_t *ctx, u16 n_data)
+{
+ hicn_hs_cbr_proto_data_t *data = proto_data(ctx);
+ data->in_flight_interests -= n_data;
+ schedule_next_interests(ctx);
+ return 0;
+}
+
+u32 cbr_proto_on_interest(hicn_hs_ctx_t *ctx)
+{
+ return 0;
+}
+
+u32 cbr_proto_interest_timeout(hicn_hs_ctx_t *ctx)
+{
+ return 0;
+}
+
+u32 cbr_proto_event(hicn_hs_ctx_t *ctx, hicn_hs_proto_event_t event)
+{
+ return 0;
+}
+
+hicn_hs_proto_t cbr_proto = {
+ .init = cbr_proto_init,
+ .rcv_data = cbr_proto_on_data,
+ .rcv_interest = cbr_proto_on_interest,
+ .on_interest_timeout = cbr_proto_interest_timeout,
+ .event = cbr_proto_event,
+ .options = {
+ .is_stream = 1}}; \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/cli.c b/hicn-plugin/src/host_stack/cli.c
new file mode 100644
index 000000000..e569d83f1
--- /dev/null
+++ b/hicn-plugin/src/host_stack/cli.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017-2019 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 "host_stack.h"
+#include "route.h"
+
+#include <vnet/session/session.h>
+
+static clib_error_t *
+hicn_hs_enable_disable_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u8 is_en = 1;
+ clib_error_t *error;
+
+ session_cli_return_if_not_enabled ();
+
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "expected enable | disable");
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "enable"))
+ is_en = 1;
+ else if (unformat (line_input, "disable"))
+ is_en = 0;
+ else
+ {
+ error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ unformat_free (line_input);
+ return error;
+ }
+ }
+
+ unformat_free (line_input);
+ return hicn_hs_enable_disable (vm, is_en);
+}
+
+static clib_error_t *
+hicn_hs_set_local_prefix_fn (vlib_main_t * vm,
+ unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ clib_error_t *error = 0;
+ fib_prefix_t prefix;
+
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return clib_error_return (0, "expected ip_address/prefix_len");
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "%U/%d", unformat_ip46_address,
+ &prefix.fp_addr, IP46_TYPE_ANY, &prefix.fp_len))
+ {
+ prefix.fp_proto = ip46_address_is_ip4(&prefix.fp_addr) ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
+ error = hicn_hs_set_local_prefix(&prefix);
+ }
+ else
+ {
+ error = clib_error_return (0, "unknown input `%U'",
+ format_unformat_error, line_input);
+ }
+ }
+
+ unformat_free (line_input);
+ return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (hicn_hs_onoff, static) =
+{
+ .path = "hicn hs",
+ .short_help = "hicn hs [enable|disable]",
+ .function = hicn_hs_enable_disable_fn,
+};
+
+VLIB_CLI_COMMAND(hicn_hs_set_local_pfx, static) =
+{
+ .path = "hicn hs set local prefix",
+ .short_help = "hicn hs set local prefix <ip_prefix/plen>",
+ .function = hicn_hs_set_local_prefix_fn,
+};
+/* *INDENT-ON* */ \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/debug.h b/hicn-plugin/src/host_stack/debug.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/hicn-plugin/src/host_stack/debug.h
diff --git a/hicn-plugin/src/host_stack/error.c b/hicn-plugin/src/host_stack/error.c
new file mode 100644
index 000000000..fa802b553
--- /dev/null
+++ b/hicn-plugin/src/host_stack/error.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 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 "error.h"
+
+u8 *
+quic_format_err (u8 * s, va_list * args)
+{
+ u64 code = va_arg (*args, u64);
+ switch (code)
+ {
+ case 0:
+ s = format (s, "no error");
+ break;
+ default:
+ s = format (s, "unknown error 0x%lx", code);
+ break;
+ }
+ return s;
+}
diff --git a/hicn-plugin/src/host_stack/error.h b/hicn-plugin/src/host_stack/error.h
new file mode 100644
index 000000000..76c6ff986
--- /dev/null
+++ b/hicn-plugin/src/host_stack/error.h
@@ -0,0 +1,33 @@
+/*
+ * 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 __included_hs_hicn_error_h__
+#define __included_hs_hicn_error_h__
+
+#include <stdarg.h>
+
+#include <vppinfra/format.h>
+
+u8 *hicn_hs_format_err (u8 *s, va_list *args);
+
+#endif /* __included_hs_hicn_error_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/host_stack/errors/hicn_hs.def b/hicn-plugin/src/host_stack/errors/hicn_hs.def
new file mode 100644
index 000000000..11474b5d9
--- /dev/null
+++ b/hicn-plugin/src/host_stack/errors/hicn_hs.def
@@ -0,0 +1,32 @@
+/*
+ * hicn_hs_input_node_error.def: Errors in hicn_hs input node
+ *
+ * Copyright (c) 2013-2019 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.
+ */
+
+hicn_hs_error (NONE, "no error")
+hicn_hs_error (ROUTE_NOT_FOUND, "no route found for given prefix")
+hicn_hs_error (ROUTE_DPO_NO_HICN, "DPO for route is not hicn dpo")
+hicn_hs_error (ROUTE_NO_LB_DPO, "DPO is not load balance")
+hicn_hs_error (ROUTE_NO_INSERT, "Route not inserted in FIB.")
+hicn_hs_error (NO_CONTEXT, "No context found for received packet")
+hicn_hs_error (PACKETS_SENT, "Packets sent")
+hicn_hs_error (NO_HICN, "Packet is not hicn")
+hicn_hs_error (DISPATCH, "Not possible to dispatch hicn packet")
+hicn_hs_error (WRONG_THREAD, "Context not found in current worker data.")
+hicn_hs_error (ENQUEUED, "Error enqueueing data to application.")
+hicn_hs_error (FORMAT, "Error parsing packet.")
+hicn_hs_error (FIFO_FULL, "Error FIFO full.")
+hicn_hs_error (ENQUEUED_OOO, "Enqueued OOO datas.")
+hicn_hs_error (PARTIALLY_ENQUEUED, "Partially enqueued, probably because of full fifo.")
diff --git a/hicn-plugin/src/host_stack/host_stack.c b/hicn-plugin/src/host_stack/host_stack.c
new file mode 100644
index 000000000..a8c27b8d0
--- /dev/null
+++ b/hicn-plugin/src/host_stack/host_stack.c
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2019 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 <sys/socket.h>
+
+#include <vnet/session/application.h>
+#include <vnet/session/transport.h>
+#include <vnet/session/session.h>
+#include <vlib/unix/plugin.h>
+#include <vppinfra/lock.h>
+
+#include "error.h"
+#include "host_stack.h"
+#include "inlines.h"
+
+#include "utils.h"
+#include "route.h"
+
+#define _IPV6 0
+
+char *hicn_hs_error_strings[] = {
+#define hicn_hs_error(n,s) s,
+#include "errors/hicn_hs.def"
+#undef hicn_hs_error
+};
+
+// Main hicn struct
+hicn_hs_main_t hicn_hs_main;
+
+/**
+ * Initiate the connection to rmt, which is actually a content.
+ * Send first interest and program rtx.
+ */
+int
+hicn_hs_connect (transport_endpoint_cfg_t * rmt)
+{
+ hicn_hs_main_t *hmm = hicn_hs_get_main ();
+ vlib_main_t *vm = vlib_get_main ();
+ u32 thread_index = vm->thread_index;
+ int rv;
+ session_endpoint_cfg_t *sep;
+ hicn_hs_ctx_t *hc;
+ app_worker_t *app_wrk;
+ session_handle_t sh;
+ session_t *s;
+ u32 hc_index;
+ char name[128];
+
+ hicn_ip_prefix_t ip_address;
+ hicn_name_t *cons_name;
+
+ CLIB_UNUSED (u32 node_index);
+
+ /* We don't poll main thread if we have workers */
+ if (vlib_num_workers ())
+ thread_index = 1;
+
+ sep = (session_endpoint_cfg_t *)(rmt);
+
+ /* XXX Here we alloc a new ctx. Not clear yet how to trigger the consumer protocol
+ from the session layer. TBD */
+ hc_index = hicn_hs_ctx_alloc (thread_index);
+ hc = hicn_hs_get_ctx_by_index(hc_index, thread_index);
+
+ ip_copy (&hc->connection.rmt_ip, &rmt->ip, rmt->is_ip4);
+ ip_copy ((ip46_address_t*)(&ip_address.address), &rmt->ip, rmt->is_ip4);
+ ip_address.family = rmt->is_ip4 ? AF_INET : AF_INET6;
+ ip_address.len = 128;
+ cons_name = hicn_hs_ctx_get_consumer_name(hc);
+
+ hicn_name_create_from_ip_prefix(&ip_address, 0, cons_name);
+ hicn_name_ntop(cons_name, name, 128);
+ HICN_HS_DBG(1, "Set name %s through hicn connect()", name);
+
+ hc->c_rmt_port = rmt->port;
+ hc->c_is_ip4 = sep->is_ip4;
+ hc->c_proto = hmm->transport_protocol_id;
+ /*
+ FixMe: Hardcoded fib index!
+ */
+ hc->c_fib_index = fib_table_find(hc->c_is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6, 10);
+ hc->parent_app_wrk_id = sep->app_wrk_index;
+ hc->c_s_index = HICN_HS_SESSION_INVALID;
+ hc->c_c_index = hc_index;
+ hc->c_flags |= TRANSPORT_CONNECTION_F_CLESS;
+ hc->client_opaque = sep->opaque;
+
+ /* XXX Hardcoded CBR protocol for the moment */
+ hc->hs_proto = &cbr_proto;
+ hc->running = 0;
+ hc->accepted = 0;
+ hc->mss = hicn_hs_default_mtu (hmm, hc->c_is_ip4);
+ hc->current_content_size = 0;
+ hc->bytes_produced = 0;
+ hc->download_content_size = ~0;
+ vec_validate (hc->pending_interests, HICN_HS_PEND_INT_SIZE);
+
+ /* Set context configuration */
+ if (!hicn_hs_cfg.csum_offload)
+ hc->cfg_flags |= HICN_HS_CFG_F_NO_CSUM_OFFLOAD;
+
+ if (!hicn_hs_cfg.allow_tso)
+ hc->cfg_flags |= HICN_HS_CFG_F_NO_TSO;
+
+ /**
+ * Connectionless session.
+ */
+
+ /**
+ * Allocate session and fifos now.
+ * XXX To check: Maybe it is better to allocate sessions and fifos
+ * upon reception of first data.
+ */
+ s = session_alloc_for_connection (&hc->connection);
+ s->app_wrk_index = hc->parent_app_wrk_id;
+ app_wrk = app_worker_get (s->app_wrk_index);
+// app_worker_alloc_connects_segment_manager (app_wrk);
+
+ s->session_state = SESSION_STATE_OPENED;
+ if (app_worker_init_connected (app_wrk, s))
+ {
+ session_free (s);
+ return -1;
+ }
+
+ sh = session_handle (s);
+ session_lookup_add_connection (&hc->connection, sh);
+
+ rv = app_worker_connect_notify (app_wrk, s, SESSION_E_NONE, hc_index);
+
+ /* Initialize CBR protocol - consumer side */
+ hc->hs_proto->init(hc);
+
+ return rv;
+}
+
+void hicn_hs_proto_on_close (u32 conn_index, u32 thread_index)
+{
+ return;
+}
+
+/**
+ * The port is used as prefix length
+ */
+static u32
+hicn_hs_get_prefix_from_transport_endpoint(const ip46_address_t* ip, const u16 port, u8 is_ip4, fib_prefix_t *prefix)
+{
+ HICN_HS_ASSERT(port <= (is_ip4 ? IPV4_ADDR_LEN_BITS : IPV6_ADDR_LEN_BITS));
+ fib_prefix_from_ip46_addr(ip, prefix);
+ prefix->fp_len = port;
+
+ return HICN_HS_ERROR_NONE;
+}
+
+/**
+ * Start listen for interests belonging to prefix
+ */
+u32 hicn_hs_start_listen (u32 session_index, transport_endpoint_t * lcl)
+{
+// hicn_hs_worker_t *wrk = hicn_hs_get_worker_by_thread(0);
+ hicn_hs_ctx_t *ctx;
+ u32 ctx_index;
+ hicn_hs_main_t *hmm = hicn_hs_get_main ();
+
+// vnet_listen_args_t _bargs, *args = &_bargs;
+// session_handle_t udp_handle;
+ session_endpoint_cfg_t *sep;
+// session_t *udp_listen_session;
+ app_worker_t *app_wrk;
+ CLIB_UNUSED(application_t *app);
+// u32 lctx_index;
+// int rv;
+
+ sep = (session_endpoint_cfg_t *) lcl;
+ app_wrk = app_worker_get (sep->app_wrk_index);
+
+ app_worker_alloc_connects_segment_manager (app_wrk);
+ app = application_get (app_wrk->app_index);
+ HICN_HS_DBG (2, "Called hicn_hs_start_listen for app %d", app_wrk->app_index);
+
+ /**
+ * Choose a transport index.
+ * hicn_hs_get_next_trasnport_index()..
+ */
+// u32 ctx_index = hicn_hs_wrk_get_next_ctx_index(wrk);
+ /* XXX Here we alloc a new ctx. Not clear yet how to trigger the consumer protocol
+ from the session layer. TBD */
+ ctx_index = hicn_hs_ctx_alloc (0);
+ ctx = hicn_hs_get_ctx_by_index(ctx_index, 0);
+
+ ip_copy (&ctx->connection.lcl_ip, &lcl->ip, lcl->is_ip4);
+ ctx->c_lcl_port = clib_net_to_host_u16(lcl->port);
+ ctx->c_is_ip4 = lcl->is_ip4;
+ ctx->c_proto = hmm->transport_protocol_id;
+ /* FixMe: Hardcoded Fib Index! */
+ ctx->c_fib_index = fib_table_find(ctx->c_is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6, 10);
+ ctx->c_c_index = ctx_index;
+ ctx->session_index = session_index;
+ ctx->mss = hicn_hs_default_mtu (hmm, ctx->c_is_ip4);
+ ctx->current_content_size = 0;
+ ctx->bytes_produced = 0;
+
+ /* Init output buffer hash table */
+ clib_bihash_init_24_8 (&ctx->output_buffer, "prod-output-buffer",
+ /* 256 k */ 256 << 10, /* 8 MB */ 8 << 20);
+
+ /* XXX Hardcoded CBR protocol for the moment */
+ ctx->hs_proto = &cbr_proto;
+ ctx->running = 0;
+ ctx->accepted = 0;
+
+ /* Set context configuration */
+ if (!hicn_hs_cfg.csum_offload)
+ ctx->cfg_flags |= HICN_HS_CFG_F_NO_CSUM_OFFLOAD;
+
+ if (!hicn_hs_cfg.allow_tso)
+ ctx->cfg_flags |= HICN_HS_CFG_F_NO_TSO;
+
+ /**
+ * Setup DPO
+ */
+ hicn_hs_dpo_create(ctx_index, lcl->is_ip4, &ctx->dpo);
+
+ /**
+ * Get prefix from transport_endpoint_t
+ */
+ hicn_hs_get_prefix_from_transport_endpoint(&ctx->c_lcl_ip, ctx->c_lcl_port, ctx->c_is_ip4, &ctx->producer_prefix);
+
+ /**
+ * Set prefix in fib
+ */
+ hicn_hs_route_add(&ctx->producer_prefix, &ctx->dpo);
+
+ /**
+ * Check if hicn_hs input node recives interests
+ */
+
+ return ctx_index;
+}
+
+u32 hicn_hs_stop_listen (u32 conn_index)
+{
+ return 0;
+}
+
+transport_connection_t *hicn_hs_connection_get (u32 conn_idx, u32 thread_idx)
+{
+ hicn_hs_ctx_t *ctx = hicn_hs_get_ctx_by_index(conn_idx, thread_idx);
+ return &ctx->connection;
+}
+
+transport_connection_t *hicn_hs_listener_get (u32 conn_index)
+{
+ hicn_hs_ctx_t *ctx = hicn_hs_get_ctx_by_index(conn_index, 0);
+ return &ctx->connection;
+}
+
+int hicn_hs_send_params (transport_connection_t * tconn,
+ transport_send_params_t *sp)
+{
+ hicn_hs_ctx_t *ctx = (hicn_hs_ctx_t *) (tconn);
+ sp->snd_space = ~0;
+
+ /* TODO: figure out MTU of output interface! */
+ sp->snd_mss = ctx->mss;
+ sp->tx_offset = 0;
+ sp->flags = 0;
+ return 0;
+}
+
+/**
+ * Push hicn header on data packet.
+ * This function is not called for interests, which are rather crafted
+ * directly in the transport layer.
+ */
+u32 hicn_hs_push_header (transport_connection_t * tconn, vlib_buffer_t * b)
+{
+ hicn_hs_ctx_t *ctx = (hicn_hs_ctx_t *) (tconn);
+ hicn_hs_worker_t * wrk = hicn_hs_get_worker_by_context (ctx);
+ u32 index;
+ int rv;
+
+ hicn_name_t *name = &ctx->current_production_name;
+ hicn_hs_buffer(b)->is_interest = 0;
+ hicn_hs_buffer(b)->ctx_index = ctx->c_c_index;
+ hicn_hs_buffer(b)->flush = 0;
+ vlib_buffer_push_hicn(ctx, b, name, ctx->snd_nxt, 0);
+
+ index = vlib_get_buffer_index (wrk->vm, b);
+ obuffer_kv4_t kv;
+ make_obuffer_kv (&kv, &ctx->current_production_name.prefix, ctx->snd_nxt++, index);
+ rv = clib_bihash_add_del_24_8 (&ctx->output_buffer, &kv, 2);
+
+ if (PREDICT_FALSE (rv < 0))
+ {
+ /* We tried to overwrite something already in the table. */
+ obuffer_kv4_t kv_ret;
+ rv = clib_bihash_search_inline_2_24_8 (&ctx->output_buffer, &kv, &kv_ret);
+ if (!rv)
+ {
+ hicn_header_t *interest, *data;
+ vlib_buffer_t *buffer;
+ hicn_hs_buffer(b)->flush = 1;
+ clib_bihash_add_del_24_8 (&ctx->output_buffer, &kv, 1);
+
+ buffer = vlib_get_buffer (wrk->vm, kv_ret.value);
+ interest = vlib_buffer_get_current (buffer);
+ data = vlib_buffer_get_current (b);
+ data->v6.ip.daddr = interest->v6.ip.saddr;
+
+ vlib_buffer_free_one (wrk->vm, kv_ret.value);
+ }
+ }
+
+ return 0;
+}
+
+void hicn_hs_update_time (f64 time_now, u8 thread_index)
+{
+ return;
+}
+
+int hicn_hs_custom_app_rx_callback (transport_connection_t *tconn)
+{
+ return 0;
+}
+
+int hicn_hs_custom_tx_callback (void *session, transport_send_params_t *sp)
+{
+ return 0;
+}
+
+u8 *format_hicn_hs_connection (u8 * s, va_list * args)
+{
+ return NULL;
+}
+
+u8 *format_hicn_hs_half_open (u8 * s, va_list * args)
+{
+ return NULL;
+}
+
+u8 *format_hicn_hs_listener (u8 * s, va_list * args)
+{
+ return NULL;
+}
+
+void hicn_hs_get_transport_endpoint (u32 conn_index, u32 thread_index,
+ transport_endpoint_t *tep, u8 is_lcl)
+{
+ return;
+}
+
+void hicn_hs_get_transport_listener_endpoint (u32 conn_index,
+ transport_endpoint_t *tep,
+ u8 is_lcl)
+{
+ return;
+}
+
+static void
+hicn_hs_expired_timers_dispatch (u32 * expired_timers)
+{
+ HICN_HS_DBG(1, "Timer expired.");
+}
+
+static const transport_proto_vft_t hicn_hs_proto = {
+ .connect = hicn_hs_connect,
+ .close = hicn_hs_proto_on_close,
+ .start_listen = hicn_hs_start_listen,
+ .stop_listen = hicn_hs_stop_listen,
+ .get_connection = hicn_hs_connection_get,
+ .get_listener = hicn_hs_listener_get,
+ .update_time = hicn_hs_update_time,
+ .app_rx_evt = hicn_hs_custom_app_rx_callback,
+ .custom_tx = hicn_hs_custom_tx_callback,
+ .send_params = hicn_hs_send_params,
+ .push_header = hicn_hs_push_header,
+ .format_connection = format_hicn_hs_connection,
+ .format_half_open = format_hicn_hs_half_open,
+ .format_listener = format_hicn_hs_listener,
+ .get_transport_endpoint = hicn_hs_get_transport_endpoint,
+ .get_transport_listener_endpoint = hicn_hs_get_transport_listener_endpoint,
+ .transport_options = {
+ /* Used by session_register_transport to select the tx function.
+ TRANSPORT_TX_INTERNAL will delegate the transmission to the transport
+ protocol itself, throught he function hicn_hs_custom_tx_callback. Magic. */
+ .tx_type = TRANSPORT_TX_DEQUEUE,
+ .service_type = TRANSPORT_SERVICE_APP,
+ .name = "hicn",
+ .short_name = "H"
+ },
+};
+
+/**
+ * Initialize default values for tcp parameters
+ */
+static void
+hicn_hs_configuration_init (void)
+{
+ hicn_hs_cfg.max_rx_fifo = 32 << 20;
+ hicn_hs_cfg.min_rx_fifo = 4 << 10;
+
+ hicn_hs_cfg.default_mtu = 1500;
+ hicn_hs_cfg.enable_tx_pacing = 0;
+ hicn_hs_cfg.allow_tso = 0;
+ hicn_hs_cfg.csum_offload = 1;
+
+ /* Time constants defined as timer tick (100ms) multiples */
+ hicn_hs_cfg.closewait_time = 20; /* 2s */
+ hicn_hs_cfg.cleanup_time = 0.1; /* 100ms */
+}
+
+clib_error_t *
+hicn_hs_enable (vlib_main_t * vm)
+{
+ HICN_HS_DBG (1, "Function called (%p).", &hicn_hs_proto);
+
+ hicn_hs_main_t *hm = &hicn_hs_main;
+
+ hicn_hs_configuration_init ();
+
+ // Register hicn_hs DPO
+ hicn_hs_dpo_module_init();
+
+ // Init route module
+ hicn_hs_route_init();
+
+ hm->enabled = 1;
+ return 0;
+}
+
+clib_error_t *
+hicn_hs_enable_disable(vlib_main_t * vm, u8 is_en)
+{
+ if (is_en)
+ {
+ if (session_main_is_enabled())
+ return hicn_hs_enable (vm);
+ else
+ return clib_error_return (0, "Session not enabled, so hicn hoststack not enabled.");
+ }
+
+ return 0;
+}
+
+void
+hicn_hs_init (vlib_main_t * vm)
+{
+ HICN_HS_DBG(1, "Function called");
+ hicn_hs_main_t *hm = &hicn_hs_main;
+ vlib_thread_main_t *vtm = vlib_get_thread_main ();
+ u32 i, num_threads = 1 /* main thread */ + vtm->n_threads;
+ tw_timer_wheel_1t_3w_1024sl_ov_t *tw;
+
+ hm->app_index = 0;
+ vec_validate_aligned (hm->workers, num_threads - 1, CLIB_CACHE_LINE_BYTES);
+
+ for (i = 0; i < num_threads; i++)
+ {
+ tw = &hm->workers[i].timer_wheel;
+ tw_timer_wheel_init_1t_3w_1024sl_ov (tw, hicn_hs_expired_timers_dispatch,
+ 1e-3 /* timer period 1ms */ , ~0);
+ tw->last_run_time = vlib_time_now (vlib_get_main ());
+ hm->workers[i].vm = vlib_mains[i];
+ hm->workers[i].next_hicn_ctx = 0;
+ }
+
+ hm->tstamp_ticks_per_clock = vm->clib_time.seconds_per_clock / HICN_HS_TSTAMP_RESOLUTION;
+
+ hm->hicn_hs_in4_idx = hicn_hs_input4_node.index;
+ hm->hicn_hs_on4_idx = hicn_hs_output4_node.index;
+
+ hm->hicn_hs_in6_idx = hicn_hs_input6_node.index;
+ hm->hicn_hs_on6_idx = hicn_hs_output6_node.index;
+
+ // Not enabled by default
+ hm->enabled = 0;
+
+ // Register new protocol
+ hm->transport_protocol_id = transport_register_new_protocol(&hicn_hs_proto,
+ FIB_PROTOCOL_IP6,
+ hm->hicn_hs_on6_idx);
+ transport_register_protocol (hm->transport_protocol_id, &hicn_hs_proto,
+ FIB_PROTOCOL_IP4, hm->hicn_hs_on4_idx);
+}
+
+/* *INDENT-ON* */
+
+// static clib_error_t *
+// hicn_hs_config_fn (vlib_main_t * vm, unformat_input_t * input)
+// {
+// HICN_HS_DBG(1, "Function called early.");
+// return 0;
+// }
+
+// static clib_error_t *
+// hicn_hs_config2_fn (vlib_main_t * vm, unformat_input_t * input)
+// {
+// HICN_HS_DBG(1, "Function called.");
+// return 0;
+// }
+
+// VLIB_EARLY_CONFIG_FUNCTION (hicn_hs_config_fn, "hicn_hs");
+// VLIB_CONFIG_FUNCTION (hicn_hs_config2_fn, "hicn_hs");
diff --git a/hicn-plugin/src/host_stack/host_stack.h b/hicn-plugin/src/host_stack/host_stack.h
new file mode 100644
index 000000000..5ad2db1ae
--- /dev/null
+++ b/hicn-plugin/src/host_stack/host_stack.h
@@ -0,0 +1,406 @@
+/*
+ * 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 __included_hicn_hs_h__
+#define __included_hicn_hs_h__
+
+#include "producer_dpo.h"
+#include "hicn_buffer.h"
+
+#include <vnet/session/application_interface.h>
+#include <vnet/session/transport.h>
+
+#include <vppinfra/lock.h>
+#include <vppinfra/tw_timer_1t_3w_1024sl_ov.h>
+#include <vppinfra/bihash_24_8.h>
+#include <vnet/crypto/crypto.h>
+#include <vppinfra/lock.h>
+
+
+/* Log levels
+ * 1 - errors
+ * 2 - connection/stream events
+ * 3 - packet events
+ * 4 - timer events
+ **/
+
+#define HICN_HS_DEBUG 1
+#define HICN_HS_TSTAMP_RESOLUTION 0.001 /* HICN_HS tick resolution (1ms) */
+#define HICN_HS_TIMER_HANDLE_INVALID ((u32) ~0)
+#define HICN_HS_SESSION_INVALID ((u32) ~0 - 1)
+#define HICN_HS_MAX_PACKET_SIZE 1280
+
+#define HICN_HS_INT_MAX 0x3FFFFFFFFFFFFFFF
+#define HICN_HS_DEFAULT_FIFO_SIZE (64 << 10)
+#define HICN_HS_DEFAULT_CONN_TIMEOUT (30 * 1000) /* 30 seconds */
+#define HICN_HS_SEND_PACKET_VEC_SIZE 16
+#define HICN_HS_IV_LEN 17
+
+#define HICN_HS_INPUT4_NODE_NAME "hicn_hs-input4"
+#define HICN_HS_OUTPUT4_NODE_NAME "hicn_hs-output4"
+
+#define HICN_HS_INPUT6_NODE_NAME "hicn_hs-input6"
+#define HICN_HS_OUTPUT6_NODE_NAME "hicn_hs-output6"
+
+#define HICN_HS_INPUT_INTEREST_NODE_NAME "hicn_hs-input-interest"
+#define HICN_HS_INPUT_DATA_NODE_NAME "hicn_hs-input-data"
+
+#define HICN_HS_DEFAULT_MTU (1500 - 40 - 20)
+
+#define PROTO_DATA_SIZE 32
+#define HICN_HS_PEND_INT_SIZE (1 << 11)
+#define HICN_HS_PEND_INT_MASK (HICN_HS_PEND_INT_SIZE - 1)
+
+#if HICN_HS_DEBUG
+#define HICN_HS_DBG(_lvl, _fmt, _args...) \
+ if (_lvl <= HICN_HS_DEBUG) \
+ clib_warning (_fmt, ##_args)
+#else
+#define HICN_HS_DBG(_lvl, _fmt, _args...)
+#endif
+
+#if CLIB_ASSERT_ENABLE
+#define HICN_HS_ASSERT(truth) ASSERT (truth)
+#else
+#define HICN_HS_ASSERT(truth) \
+ do { \
+ if (PREDICT_FALSE (! (truth))) \
+ HICN_HS_ERR ("ASSERT(%s) failed", # truth); \
+ } while (0)
+#endif
+
+#define HICN_HS_ERR(_fmt, _args...) \
+ do { \
+ clib_warning ("HICN_HS-ERR: " _fmt, ##_args); \
+ } while (0)
+
+extern vlib_node_registration_t hicn_hs_input_node;
+extern vlib_node_registration_t hicn_hs_input_interest_node;
+extern vlib_node_registration_t hicn_hs_input_data_node;
+
+typedef enum
+{
+#define hicn_hs_error(n,s) HICN_HS_ERROR_##n,
+#include "errors/hicn_hs.def"
+#undef hicn_hs_error
+ HICN_HS_N_ERROR,
+} hicn_hs_error_t;
+
+typedef struct hicn_hs_proto_ hicn_hs_proto_t;
+
+/* hicn configuration flags */
+#define foreach_hicn_hs_cfg_flag \
+ _(NO_CSUM_OFFLOAD, "No csum offload") \
+ _(NO_TSO, "TSO off")
+
+typedef enum hicn_hs_cfg_flag_bits_
+{
+#define _(sym, str) HICN_HS_CFG_F_##sym##_BIT,
+ foreach_hicn_hs_cfg_flag
+#undef _
+ HICN_HS_CFG_N_FLAG_BITS
+} hicn_hs_cfg_flag_bits_e;
+
+typedef enum hicn_hs_cfg_flag_
+{
+#define _(sym, str) HICN_HS_CFG_F_##sym = 1 << HICN_HS_CFG_F_##sym##_BIT,
+ foreach_hicn_hs_cfg_flag
+#undef _
+ HICN_HS_CFG_N_FLAGS
+} hicn_hs_cfg_flags_e;
+
+typedef enum hicn_hs_proto_event_
+{
+ PROTO_N_EVENT,
+} hicn_hs_proto_event_t;
+
+typedef struct hicn_hs_ctx_
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ transport_connection_t connection; /* Must be first, for convenient casts!!! */
+ u32 parent_app_wrk_id;
+ u32 client_opaque;
+ u32 timer_handle;
+ u8 cfg_flags; /**< Hicn ctx configuration flags */
+ hicn_hs_proto_t *hs_proto;
+ u8 hs_proto_data[PROTO_DATA_SIZE];
+
+ /* Maps interest suffix -> vlib buffer index */
+ u32 *pending_interests;
+
+ // The hicn name for the consumer session
+ hicn_name_t consumer_name;
+ // The current name in production in th eproducer session
+ hicn_name_t current_production_name;
+
+ // The prefix for the producer names.
+ /* XXX To be retrieved from a pool of names configured by the control protocol / network admin */
+ fib_prefix_t producer_prefix;
+
+ /* Store the size of the content currently produced. */
+ u32 current_content_size;
+ u32 number_of_segments;
+
+ /* Store size of content to download - consumer side */
+ u32 download_content_size;
+
+ u32 bytes_produced;
+
+ /* Seq number to assign to next segment */
+ u32 snd_nxt;
+
+ /* Expected bytes */
+ u32 rcv_nxt;
+
+ /* Some stats */
+ u64 int_in;
+ u64 data_in;
+ u64 int_out;
+ u64 data_out;
+ u64 bytes_in;
+ u64 bytes_outs;
+
+ /* The DPO for this hicn_hs ctx */
+ dpo_id_t dpo;
+
+ /* Hash table for exact match prefix-suffix */
+ clib_bihash_24_8_t output_buffer;
+
+ /* Unused listener session index */
+ u32 session_index;
+
+ u8 running;
+ u8 accepted;
+
+ u16 mss;
+} hicn_hs_ctx_t;
+
+typedef clib_bihash_kv_24_8_t obuffer_kv4_t;
+
+typedef struct {
+ u32 ctx_index;
+ u8 is_interest;
+ u8 is_ip4;
+ u8 flush;
+ u32 seq_number;
+ hicn_type_t type;
+} hicn_hs_buffer_t;
+
+#define hicn_hs_buffer(b) ((hicn_hs_buffer_t *) (b)->opaque2)
+#define hicn_buffer_hdr(b) ((hicn_header_t *) (vlib_buffer_get_current(b)))
+
+always_inline void *
+hicn_hs_proto_data(hicn_hs_ctx_t *ctx)
+{
+ return (void*)(ctx->hs_proto_data);
+}
+
+struct hicn_hs_proto_
+{
+ u32 (*init) (hicn_hs_ctx_t * hc);
+ u32 (*rcv_data) (hicn_hs_ctx_t * hc, u16 n_data);
+ u32 (*rcv_interest) (hicn_hs_ctx_t * hc);
+ u32 (*on_interest_timeout) (hicn_hs_ctx_t *hc);
+ u32 (*event) (hicn_hs_ctx_t *hc, hicn_hs_proto_event_t event);
+ struct {
+ u8 is_stream;
+ } options;
+};
+
+typedef struct hicn_hs_worker_ctx_
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ hicn_hs_ctx_t *hicn_ctxs; /**< worker's pool of hicn context */
+ u32 next_hicn_ctx; /**< Next hicn context, to be used in start_listen*/
+ int64_t time_now; /**< worker time */
+ tw_timer_wheel_1t_3w_1024sl_ov_t timer_wheel; /**< worker timer wheel */
+ vlib_main_t *vm; /**< pointer to thread's vlib main*/
+ /** Peekers rw lock */
+ clib_rwlock_t peekers_rw_locks;
+} hicn_hs_worker_t;
+
+typedef struct hicn_hs_configuration_
+{
+ /** Max rx fifo size for a session (in bytes). It is used in to compute the
+ * rfc 7323 window scaling factor */
+ u32 max_rx_fifo;
+
+ /** Min rx fifo for a session (in bytes) */
+ u32 min_rx_fifo;
+
+ /** Default MTU to be used when establishing connections */
+ u16 default_mtu;
+
+ /** Enable tx pacing for new connections */
+ u8 enable_tx_pacing;
+
+ /** Allow use of TSO whenever available */
+ u8 allow_tso;
+
+ /** Set if csum offloading is enabled */
+ u8 csum_offload;
+
+ /** Timer ticks to wait for close from app */
+ u16 closewait_time;
+
+ /** Time to wait (sec) before cleaning up the connection */
+ f32 cleanup_time;
+} hicn_hs_configuration_t;
+
+typedef struct _hicn_hs_lookup_dispatch
+{
+ u8 next, error;
+} hicn_hs_lookup_dispatch_t;
+
+#define foreach_hicn_hs_packet \
+ _ (DATA, "data") \
+ _ (INTEREST, "interest") \
+ _ (NO_HICN, "ho hicn")
+
+typedef enum _hicn_hs_packet
+{
+ #define _(n, s) HICN_HS_##n,
+ foreach_hicn_hs_packet
+ #undef _
+ HICN_HS_N_PACKET,
+} hicn_hs_packet_t;
+
+typedef struct hicn_hs_main_
+{
+ u32 app_index;
+ hicn_hs_worker_t *workers;
+ clib_bihash_24_8_t connection_hash; /**< connection id -> conn handle */
+ f64 tstamp_ticks_per_clock;
+
+ // The new registered transport ID
+ transport_proto_t transport_protocol_id;
+
+ // Input/Output nodes information
+ u32 hicn_hs_in4_idx;
+ u32 hicn_hs_on4_idx;
+ u32 hicn_hs_in6_idx;
+ u32 hicn_hs_on6_idx;
+
+ // Enabled/Disabled
+ u8 enabled;
+
+ u32 udp_fifo_size;
+ u32 udp_fifo_prealloc;
+ u32 connection_timeout;
+
+ // Configuration
+ hicn_hs_configuration_t cfg;
+
+ // Dispatch table
+ hicn_hs_lookup_dispatch_t dispatch_table[HICN_HS_N_PACKET];
+} hicn_hs_main_t;
+
+void hicn_hs_init (vlib_main_t * vm);
+
+extern hicn_hs_main_t hicn_hs_main;
+extern vlib_node_registration_t hicn_hs_input4_node;
+extern vlib_node_registration_t hicn_hs_output4_node;
+extern vlib_node_registration_t hicn_hs_input6_node;
+extern vlib_node_registration_t hicn_hs_output6_node;
+extern char *hicn_hs_error_strings[];
+
+#define hicn_hs_cfg (hicn_hs_main.cfg)
+
+// Protocols
+extern hicn_hs_proto_t cbr_proto;
+
+always_inline
+hicn_hs_main_t *hicn_hs_get_main ()
+{
+ return &hicn_hs_main;
+}
+
+always_inline
+transport_proto_t hicn_hs_get_protocol_id()
+{
+ hicn_hs_main_t *hm = hicn_hs_get_main ();
+ return hm->transport_protocol_id;
+}
+
+clib_error_t * hicn_hs_enable_disable(vlib_main_t * vm, u8 is_en);
+
+always_inline void
+hicn_hs_update_transport(hicn_hs_ctx_t *ctx, u16 recv_data)
+{
+ // Pass data packet to transport
+ ctx->hs_proto->rcv_data(ctx, recv_data);
+}
+
+always_inline void
+hicn_hs_set_next_prod_size (hicn_hs_ctx_t *ctx, u32 prod_size)
+{
+ ctx->current_content_size = prod_size;
+ ctx->number_of_segments = (prod_size / ctx->mss) + ((prod_size % ctx->mss) > 0);
+}
+
+always_inline hicn_hs_worker_t *
+hicn_hs_get_worker_by_context (hicn_hs_ctx_t *ctx)
+{
+ hicn_hs_main_t *hmm = hicn_hs_get_main ();
+ return &hmm->workers[ctx->c_thread_index];
+}
+
+always_inline hicn_hs_worker_t *
+hicn_hs_get_worker_by_thread (u32 thread_idx)
+{
+ hicn_hs_main_t *hmm = hicn_hs_get_main ();
+ return &hmm->workers[thread_idx];
+}
+
+always_inline hicn_hs_ctx_t *
+hicn_hs_wrk_get_ctx(hicn_hs_worker_t *wrk, u32 index)
+{
+ return pool_elt_at_index (wrk->hicn_ctxs, index);
+}
+
+always_inline u32
+hicn_hs_wrk_get_next_ctx_index(hicn_hs_worker_t *wrk)
+{
+ return wrk->next_hicn_ctx++;
+}
+
+always_inline hicn_hs_ctx_t *
+hicn_hs_get_ctx_by_index (u32 ctx_index, u32 thread_index)
+{
+ hicn_hs_worker_t *wrk = hicn_hs_get_worker_by_thread(thread_index);
+ return hicn_hs_wrk_get_ctx(wrk, ctx_index);
+}
+
+always_inline hicn_name_t*
+hicn_hs_ctx_get_consumer_name(hicn_hs_ctx_t *ctx)
+{
+ return &ctx->consumer_name;
+}
+
+always_inline dpo_id_t*
+hicn_hs_ctx_get_dpo(hicn_hs_ctx_t *ctx)
+{
+ return &ctx->dpo;
+}
+
+#endif /* __included_hicn_hs_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/host_stack/inlines.h b/hicn-plugin/src/host_stack/inlines.h
new file mode 100644
index 000000000..5c2c33915
--- /dev/null
+++ b/hicn-plugin/src/host_stack/inlines.h
@@ -0,0 +1,520 @@
+/*
+ * 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 __included_hicn_hs_inlines_h__
+#define __included_hicn_hs_inlines_h__
+
+#include "host_stack.h"
+#include "utils.h"
+
+always_inline void
+make_obuffer_kv (obuffer_kv4_t * kv, ip46_address_t * prefix, u32 suffix, u32 bi)
+{
+ kv->key[0] = prefix->as_u64[0];
+ kv->key[1] = prefix->as_u64[1];
+ kv->key[2] = suffix;
+ kv->value = bi;
+}
+
+always_inline void
+hicn_hs_app_notify_rx (hicn_hs_ctx_t *ctx)
+{
+ session_t *s;
+ s = session_get(ctx->c_s_index, 0);
+ session_enqueue_notify(s);
+}
+
+always_inline u16
+hicn_hs_default_mtu (hicn_hs_main_t * hm, u8 is_ip4)
+{
+ u16 hicn_hlen = is_ip4 ? HICN_V4_TCP_HDRLEN : HICN_V6_TCP_HDRLEN;
+ return (hicn_hs_cfg.default_mtu - hicn_hlen);
+}
+
+always_inline u32
+hicn_hs_ctx_alloc(u32 thread_index)
+{
+ hicn_hs_worker_t *wrk = hicn_hs_get_worker_by_thread(thread_index);
+ hicn_hs_ctx_t *ctx;
+
+ u8 will_expand;
+ pool_get_aligned_will_expand (wrk->hicn_ctxs, will_expand,
+ CLIB_CACHE_LINE_BYTES);
+ /* If we have peekers, let them finish */
+ if (PREDICT_FALSE (will_expand && vlib_num_workers ()))
+ {
+ clib_rwlock_writer_lock (&wrk->peekers_rw_locks);
+ pool_get_aligned (wrk->hicn_ctxs, ctx, CLIB_CACHE_LINE_BYTES);
+ clib_rwlock_writer_unlock (&wrk->peekers_rw_locks);
+ }
+ else
+ {
+ pool_get_aligned (wrk->hicn_ctxs, ctx, CLIB_CACHE_LINE_BYTES);
+ }
+
+ clib_memset (ctx, 0, sizeof (hicn_hs_ctx_t));
+ ctx->c_thread_index = thread_index;
+ ctx->timer_handle = HICN_HS_TIMER_HANDLE_INVALID;
+ HICN_HS_DBG (3, "Allocated hicn_hs_ctx_t %u on thread %u",
+ ctx - wrk->hicn_ctxs, thread_index);
+
+ return ctx - wrk->hicn_ctxs;
+}
+
+always_inline void*
+vlib_buffer_push_hicn (hicn_hs_ctx_t *ctx, vlib_buffer_t *b,
+ hicn_name_t* name, u32 seq_number, u8 is_interest)
+{
+ hicn_header_t *hicn_header;
+ hicn_hs_buffer_t *buffer = hicn_hs_buffer (b);
+ int rv;
+ u16 current_length = b->current_length;
+ u16 payload_len = current_length;
+ if (PREDICT_FALSE (b->flags & VLIB_BUFFER_TOTAL_LENGTH_VALID))
+ payload_len += b->total_length_not_including_first_buffer;
+
+ hicn_header = vlib_buffer_push_uninit (b, HICN_V6_TCP_HDRLEN);
+ buffer->type.l4 = IPPROTO_NONE;
+ buffer->type.l3 = IPPROTO_NONE;
+ buffer->type.l2 = IPPROTO_TCP;
+ buffer->type.l1 = IPPROTO_IPV6;
+
+ buffer->flush = 0;
+
+ name->suffix = seq_number;
+
+ rv = hicn_ops_vft[buffer->type.l1]->init_packet_header(buffer->type, &hicn_header->protocol);
+ rv += hicn_ops_vft[buffer->type.l1]->set_payload_length(buffer->type, &hicn_header->protocol, payload_len);
+
+ if (is_interest)
+ {
+ rv += hicn_ops_vft[buffer->type.l1]->set_interest_name(buffer->type, &hicn_header->protocol, name);
+ rv += hicn_ops_vft[buffer->type.l1]->mark_packet_as_interest(buffer->type, &hicn_header->protocol);
+ }
+ else
+ {
+ rv += hicn_ops_vft[buffer->type.l1]->set_data_name(buffer->type, &hicn_header->protocol, name);
+ rv += hicn_ops_vft[buffer->type.l1]->mark_packet_as_data(buffer->type, &hicn_header->protocol);
+ }
+
+ ASSERT (!rv);
+
+ hicn_header->v6.tcp.csum = hicn_hs_compute_checksum (ctx, b);
+
+ vnet_buffer (b)->l4_hdr_offset = (u8 *) hicn_header - b->data;
+ b->flags |= VNET_BUFFER_F_L4_HDR_OFFSET_VALID;
+
+ ctx->bytes_produced += current_length;
+
+ if (PREDICT_FALSE (!is_interest && ctx->bytes_produced == ctx->current_content_size))
+ {
+ // Last packet
+// rv += hicn_packet_set_rst (hicn_header);
+ }
+
+ return hicn_header;
+}
+
+always_inline u32
+hicn_hs_make_interest (hicn_hs_ctx_t * ctx, vlib_buffer_t *b,
+ hicn_name_t *name, u32 seq_number)
+{
+ vlib_buffer_push_hicn(ctx, b, name, seq_number, 1);
+ hicn_hs_buffer (b)->flush = 1;
+ b->ref_count = 1;
+ return 1;
+}
+
+always_inline void
+hicn_hs_enqueue_to_output (vlib_main_t *vm, session_main_t *smm,
+ vlib_buffer_t * b, u32 bi, u8 is_ip4,
+ session_type_t st)
+{
+ session_add_pending_tx_buffer (vm->thread_index, bi, smm->session_type_to_next[st]);
+}
+
+always_inline u32
+hicn_hs_send_interests_i (vlib_main_t *vm, hicn_hs_ctx_t *ctx, vlib_buffer_t **b, u32 *bi, u32 offset, u32 count)
+{
+ int ret = 0;
+ hicn_name_t *name = hicn_hs_ctx_get_consumer_name(ctx);
+ session_type_t st;
+ hicn_hs_main_t *hm = hicn_hs_get_main();
+ session_main_t *smm = vnet_get_session_main ();
+ transport_proto_t proto = hm->transport_protocol_id;
+
+ st = session_type_from_proto_and_ip (proto, ctx->c_is_ip4);
+
+ while (count >= 8)
+ {
+ {
+ vlib_prefetch_buffer_header (b[4], STORE);
+ CLIB_PREFETCH (b[4]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+
+ vlib_prefetch_buffer_header (b[5], STORE);
+ CLIB_PREFETCH (b[5]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+
+ vlib_prefetch_buffer_header (b[6], STORE);
+ CLIB_PREFETCH (b[6]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+
+ vlib_prefetch_buffer_header (b[7], STORE);
+ CLIB_PREFETCH (b[7]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ ASSERT ((b[0]->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
+ b[0]->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ b[0]->total_length_not_including_first_buffer = 0;
+ b[0]->current_data = 0;
+ b[0]->error = 0;
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
+ hicn_hs_buffer(b[0])->ctx_index = ctx->c_c_index;
+ hicn_hs_buffer(b[0])->is_interest = 1;
+ /* Leave enough space for headers */
+ vlib_buffer_make_headroom (b[0], TRANSPORT_MAX_HDRS_LEN);
+ ret += hicn_hs_make_interest (ctx, b[0], name, offset++);
+ hicn_hs_enqueue_to_output (vm, smm, b[0], bi[0], ctx->c_is_ip4, st);
+
+ ASSERT ((b[1]->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
+ b[1]->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ b[1]->total_length_not_including_first_buffer = 0;
+ b[1]->current_data = 0;
+ b[1]->error = 0;
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[1]);
+ hicn_hs_buffer(b[1])->ctx_index = ctx->c_c_index;
+ hicn_hs_buffer(b[1])->is_interest = 1;
+ /* Leave enough space for headers */
+ vlib_buffer_make_headroom (b[1], TRANSPORT_MAX_HDRS_LEN);
+ ret += hicn_hs_make_interest (ctx, b[1], name, offset++);
+ hicn_hs_enqueue_to_output (vm, smm, b[1], bi[1], ctx->c_is_ip4, st);
+
+ ASSERT ((b[2]->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
+ b[2]->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ b[2]->total_length_not_including_first_buffer = 0;
+ b[2]->current_data = 0;
+ b[2]->error = 0;
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[2]);
+ hicn_hs_buffer(b[2])->ctx_index = ctx->c_c_index;
+ hicn_hs_buffer(b[2])->is_interest = 1;
+ /* Leave enough space for headers */
+ vlib_buffer_make_headroom (b[2], TRANSPORT_MAX_HDRS_LEN);
+ ret += hicn_hs_make_interest (ctx, b[2], name, offset++);
+ hicn_hs_enqueue_to_output (vm, smm, b[2], bi[2], ctx->c_is_ip4, st);
+
+ ASSERT ((b[3]->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
+ b[3]->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ b[3]->total_length_not_including_first_buffer = 0;
+ b[3]->current_data = 0;
+ b[3]->error = 0;
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[3]);
+ hicn_hs_buffer(b[3])->ctx_index = ctx->c_c_index;
+ hicn_hs_buffer(b[3])->is_interest = 1;
+ /* Leave enough space for headers */
+ vlib_buffer_make_headroom (b[3], TRANSPORT_MAX_HDRS_LEN);
+ ret += hicn_hs_make_interest (ctx, b[3], name, offset++);
+ hicn_hs_enqueue_to_output (vm, smm, b[3], bi[3], ctx->c_is_ip4, st);
+
+ b += 4;
+ bi += 4;
+ count -= 4;
+ }
+ while (count)
+ {
+ if (count > 1)
+ {
+ vlib_prefetch_buffer_header (b[1], STORE);
+ CLIB_PREFETCH (b[1]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+ }
+ ASSERT ((b[0]->flags & VLIB_BUFFER_NEXT_PRESENT) == 0);
+ b[0]->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
+ b[0]->total_length_not_including_first_buffer = 0;
+ b[0]->current_data = 0;
+ b[0]->error = 0;
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b[0]);
+ hicn_hs_buffer(b[0])->ctx_index = ctx->c_c_index;
+ hicn_hs_buffer(b[0])->is_interest = 1;
+ /* Leave enough space for headers */
+ vlib_buffer_make_headroom (b[0], TRANSPORT_MAX_HDRS_LEN);
+ ret += hicn_hs_make_interest (ctx, b[0], name, offset++);
+ hicn_hs_enqueue_to_output (vm, smm, b[0], bi[0], ctx->c_is_ip4, st);
+
+ b += 1;
+ bi += 1;
+ count -= 1;
+ }
+
+ return ret;
+}
+
+always_inline u32
+hicn_hs_send_interests (hicn_hs_ctx_t * ctx, u32 start_offset, u32 n_interest)
+{
+ hicn_hs_worker_t *wrk = hicn_hs_get_worker_by_context (ctx);
+ vlib_main_t *vm = wrk->vm;
+ vlib_buffer_t *b[VLIB_FRAME_SIZE];
+ u32 bi[VLIB_FRAME_SIZE];
+
+ if (PREDICT_FALSE (!vlib_buffer_alloc (vm, bi, n_interest)))
+ {
+ HICN_HS_DBG (1, "Vlib buffer alloc failed.");
+ return 0;
+ }
+ vlib_get_buffers (vm, bi, b, n_interest);
+ return hicn_hs_send_interests_i (vm, ctx, b, bi, start_offset, n_interest);
+}
+
+/* Modulo arithmetic for TCP sequence numbers */
+#define seq_lt(_s1, _s2) ((i32)((_s1)-(_s2)) < 0)
+#define seq_leq(_s1, _s2) ((i32)((_s1)-(_s2)) <= 0)
+#define seq_gt(_s1, _s2) ((i32)((_s1)-(_s2)) > 0)
+#define seq_geq(_s1, _s2) ((i32)((_s1)-(_s2)) >= 0)
+#define seq_max(_s1, _s2) (seq_gt((_s1), (_s2)) ? (_s1) : (_s2))
+
+/** Enqueue data for delivery to application */
+always_inline int
+hicn_hs_enqueue_data (hicn_hs_ctx_t * ctx, vlib_buffer_t * b,
+ u16 data_len)
+{
+ int written, error = HICN_HS_ERROR_ENQUEUED;
+ hicn_hs_buffer_t *buffer = hicn_hs_buffer (b);
+
+ ASSERT (seq_geq (buffer->seq_number, ctx->rcv_nxt));
+ ASSERT (data_len);
+
+ written = session_enqueue_stream_connection (&ctx->connection, b, 0,
+ 1 /* queue event */ , 1);
+ ctx->bytes_in += written;
+
+ /* Update rcv_nxt */
+ if (PREDICT_TRUE (written == data_len))
+ {
+ ctx->rcv_nxt += written;
+ }
+ /* If more data written than expected, account for out-of-order bytes. */
+ else if (written > data_len)
+ {
+ ctx->rcv_nxt += written;
+ }
+ else if (written > 0)
+ {
+ /* We've written something but FIFO is probably full now */
+ ctx->rcv_nxt += written;
+ error = HICN_HS_ERROR_PARTIALLY_ENQUEUED;
+ }
+ else
+ {
+ error = HICN_HS_ERROR_FIFO_FULL;
+ }
+
+ if (PREDICT_FALSE (ctx->rcv_nxt >= ctx->download_content_size))
+ hicn_hs_app_notify_rx (ctx);
+
+ return error;
+}
+
+always_inline int
+hicn_hs_enqueue_ooo (hicn_hs_ctx_t * ctx, vlib_buffer_t * b,
+ u16 data_len)
+{
+ int rv, CLIB_UNUSED(offset);
+ hicn_hs_buffer_t *buffer = hicn_hs_buffer (b);
+
+ ASSERT (seq_gt (buffer->seq_number, ctx->rcv_nxt));
+ ASSERT (data_len);
+
+ /* Enqueue out-of-order data with relative offset */
+ rv = session_enqueue_stream_connection (&ctx->connection, b,
+ buffer->seq_number - ctx->rcv_nxt,
+ 0 /* queue event */ , 0);
+
+ /* Nothing written */
+ if (rv)
+ {
+ return HICN_HS_ERROR_FIFO_FULL;
+ }
+
+ ctx->bytes_in += data_len;
+
+ return HICN_HS_ERROR_ENQUEUED_OOO;
+}
+
+always_inline int
+hicn_hs_rcv_stream (hicn_hs_worker_t * wrk, hicn_hs_ctx_t * ctx,
+ vlib_buffer_t * b)
+{
+ u32 error;
+ size_t n_data_bytes, skip;
+ hicn_hs_buffer_t *buffer = hicn_hs_buffer (b);
+ hicn_header_t *hicn_header;
+ int rv;
+ u8 rst = 0;
+ hicn_name_t data_name;
+
+ /* XXX Assuming no signature for now. */
+ hicn_header = vlib_buffer_get_current (b);
+
+ rv = hicn_ops_vft[buffer->type.l1]->get_payload_length (buffer->type, &hicn_header->protocol, (size_t *)(&n_data_bytes));
+ rv += hicn_ops_vft[buffer->type.l1]->get_header_length (buffer->type, &hicn_header->protocol, (size_t *)(&skip));
+ rv += hicn_ops_vft[buffer->type.l1]->get_data_name (buffer->type, &hicn_header->protocol, &data_name);
+ rv += hicn_name_compare (&ctx->consumer_name, &data_name, 0);
+
+ vlib_buffer_advance (b, skip);
+
+ if (PREDICT_FALSE(rv < 0))
+ {
+ error = HICN_HS_ERROR_FORMAT;
+ return error;
+ }
+
+// TODO hicn_packet_test_rst (hicn_header, (bool *)(&rst));
+ if (PREDICT_FALSE (rst))
+ ctx->download_content_size = (buffer->seq_number - 1) * ctx->mss + n_data_bytes;
+
+ ASSERT (n_data_bytes);
+
+ /* Adjust seq number in order to represent byte number */
+ buffer->seq_number *= ctx->mss;
+
+ /* Handle out-of-order data */
+ if (PREDICT_FALSE (buffer->seq_number != ctx->rcv_nxt))
+ {
+ rv = hicn_hs_enqueue_ooo (ctx, b, n_data_bytes);
+ }
+ else
+ /* In order data, enqueue. Fifo figures out by itself if any out-of-order
+ * segments can be enqueued after fifo tail offset changes. */
+ rv = hicn_hs_enqueue_data (ctx, b, n_data_bytes);
+
+ vlib_buffer_push_uninit(b, skip);
+
+ return rv;
+}
+
+always_inline
+void hicn_hs_process_incoming_interest (hicn_hs_ctx_t *ctx, vlib_buffer_t* interest)
+{
+ hicn_hs_buffer_t *buffer;
+ vlib_buffer_t *data_packet;
+ hicn_hs_worker_t *wrk = hicn_hs_get_worker_by_context (ctx);
+ session_main_t *smm = vnet_get_session_main ();
+ hicn_hs_main_t *hm = hicn_hs_get_main ();
+ vlib_main_t *vm = wrk->vm;
+ obuffer_kv4_t kv;
+ int rv;
+ session_type_t st;
+ u32 suffix;
+ u32 interest_index;
+
+ transport_proto_t proto = hm->transport_protocol_id;
+ st = session_type_from_proto_and_ip (proto, ctx->c_is_ip4);
+
+ buffer = hicn_hs_buffer (interest);
+
+ if (PREDICT_FALSE(!ctx->accepted))
+ {
+ session_stream_accept(&ctx->connection, ctx->session_index, 0, 1);
+ ctx->accepted = 1;
+ }
+
+ interest_index = vlib_get_buffer_index (wrk->vm, interest);
+
+ // Check for match in local output buffer
+ if (PREDICT_FALSE(buffer->is_ip4))
+ {
+ // Handle ip4 case
+ return;
+ }
+ else
+ {
+ hicn_hs_buffer_t *b = hicn_hs_buffer (interest);
+ ip6_header_t *ip6 = vlib_buffer_get_current (interest);
+ hicn_protocol_t *proto = (hicn_protocol_t *)(ip6);
+ hicn_ops_vft[b->type.l1]->get_interest_name_suffix(b->type, proto, &suffix);
+ make_obuffer_kv(&kv, (ip46_address_t *)&ip6->dst_address, suffix, ~0);
+ rv = clib_bihash_search_inline_24_8(&ctx->output_buffer, &kv);
+ if (PREDICT_TRUE(!rv))
+ {
+ u32 bi = (u32) kv.value;
+
+ // Retrieve corresponding data packet
+ data_packet = vlib_get_buffer(vm, bi);
+
+ hicn_header_t *interest = (hicn_header_t *)(proto);
+ hicn_header_t *data = vlib_buffer_get_current (data_packet);
+
+ ASSERT(!hicn_hs_buffer (data_packet)->is_interest);
+ hicn_hs_buffer (data_packet)->ctx_index = ctx->c_c_index;
+ hicn_hs_buffer (data_packet)->flush = 1;
+
+ data->v6.ip.daddr = interest->v6.ip.saddr;
+
+ hicn_hs_enqueue_to_output (vm, smm, data_packet, bi, 0, st);
+ }
+ else
+ {
+ /**
+ * What it is better to do here is allocate connection upon
+ * interest reception, once. This will allow to get the thread index,
+ * the one which received the interest. The idea is that all interests
+ * for same content should be processed by same thread. We cannot use
+ * RSS hashing, since the source address will change..
+ * Solutions:
+ * - Dispatcher node BEFORE hicn network plugin, doing exactly the same of RSS hashing
+ * - Configure hashing function in order to consider hICN-meaningful part of the packet
+ */
+
+ if (ip46_address_is_equal ((ip46_address_t *) (&ctx->current_production_name.prefix),
+ (ip46_address_t *) (&ip6->dst_address)))
+ {
+ /**
+ * Content currently in production.
+ **/
+ if (PREDICT_FALSE(suffix >= ctx->number_of_segments))
+ goto cleanup;
+
+ kv.value = interest_index;
+ clib_bihash_add_del_24_8 (&ctx->output_buffer, &kv, 1);
+ return;
+ }
+
+ // Signal this cache miss to parent app.
+ // session_enqueue_dgram_connection(ctx->c_s_index, )
+ ip46_address_copy((ip46_address_t *) (&ctx->current_production_name.prefix),
+ (ip46_address_t *) (&ip6->dst_address));
+ ctx->current_production_name.suffix = 0;
+ kv.value = interest_index;
+ clib_bihash_add_del_24_8 (&ctx->output_buffer, &kv, 1);
+ hicn_hs_app_notify_rx (ctx);
+ return;
+ }
+ }
+
+cleanup:
+ vlib_buffer_free_one (wrk->vm, interest_index);
+}
+
+always_inline
+void hicn_hs_process_incoming_data(hicn_hs_ctx_t *ctx, vlib_buffer_t* data)
+{
+ hicn_hs_worker_t *wrk = hicn_hs_get_worker_by_context (ctx);
+ hicn_hs_rcv_stream (wrk, ctx, data);
+
+ /**
+ * If stream connection, tcp seq number in data packet stores
+ * the byte number of the first byte of data in the TCP packet sent.
+ */
+
+}
+
+#endif /* __included_hicn_hs_inlines_h__ */ \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/input_node.c b/hicn-plugin/src/host_stack/input_node.c
new file mode 100644
index 000000000..962f8a204
--- /dev/null
+++ b/hicn-plugin/src/host_stack/input_node.c
@@ -0,0 +1,477 @@
+/*
+ * 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 <vlibmemory/api.h>
+#include <vlib/vlib.h>
+
+#include "host_stack.h"
+#include "inlines.h"
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vnet/ip/ip.h>
+#include <vnet/udp/udp.h>
+#include <vnet/udp/udp_packet.h>
+#include <vnet/session/session.h>
+
+typedef enum _hicn_hs_input_next
+{
+ HICN_HS_INPUT_NEXT_DATA,
+ HICN_HS_INPUT_NEXT_INTEREST,
+ HICN_HS_INPUT_NEXT_DROP,
+ HICN_HS_INPUT_N_NEXT
+} hicn_hs_input_next_t;
+
+#define foreach_hicn_hs_input_next4 \
+ _ (DATA, HICN_HS_INPUT_DATA_NODE_NAME) \
+ _ (INTEREST, HICN_HS_INPUT_INTEREST_NODE_NAME) \
+ _ (DROP, "ip4-drop")
+
+#define foreach_hicn_hs_input_next6 \
+ _ (DATA, HICN_HS_INPUT_DATA_NODE_NAME) \
+ _ (INTEREST, HICN_HS_INPUT_INTEREST_NODE_NAME) \
+ _ (DROP, "ip6-drop")
+
+/* packet trace format function */
+static u8 *
+format_hicn_hs_input4_trace (u8 * s, va_list * args)
+{
+ return NULL;
+}
+
+static u8 *
+format_hicn_hs_input6_trace (u8 * s, va_list * args)
+{
+ return NULL;
+}
+
+static u8 *
+format_hicn_hs_input_interest_trace (u8 * s, va_list * args)
+{
+ return NULL;
+}
+
+static u8 *
+format_hicn_hs_input_data_trace (u8 * s, va_list * args)
+{
+ return NULL;
+}
+
+static void
+hicn_hs_input_trace_frame (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_buffer_t ** bs, u32 n_bufs, u8 is_ip4)
+{
+}
+
+always_inline hicn_hs_ctx_t *
+hicn_hs_input_lookup_buffer (vlib_buffer_t * b, u8 thread_index, u32 * error,
+ u8 is_ip4)
+{
+ hicn_hs_ctx_t *ctx = 0;
+ hicn_header_t *hicn;
+ hicn_hs_buffer_t *buffer;
+ u32 ctx_index;
+ int ret;
+ u8 *packet_buffer;
+ u32 seq_number;
+
+ hicn = hicn_buffer_hdr (b);
+ buffer = hicn_hs_buffer (b);
+ packet_buffer = vlib_buffer_get_current (b);
+
+ buffer->type.l4 = IPPROTO_NONE;
+ buffer->type.l3 = IPPROTO_NONE;
+ buffer->type.l2 = packet_buffer[6 + is_ip4 * 3];
+ buffer->type.l1 = (!is_ip4) * (IPPROTO_IPV6);
+
+ ret = hicn_ops_vft[buffer->type.l1]->test_packet_is_interest(buffer->type, &hicn->protocol, &buffer->is_interest);
+
+ if (PREDICT_FALSE(ret < 0))
+ {
+ *error = HICN_HS_ERROR_NO_HICN;
+ return ctx;
+ }
+
+ if (buffer->is_interest)
+ {
+ ctx_index = vnet_buffer (b)->ip.adj_index[VLIB_TX];
+ }
+ else
+ {
+ ctx_index = vnet_buffer (b)->ip.adj_index[VLIB_TX];
+ hicn_ops_vft[buffer->type.l1]->get_data_name_suffix (buffer->type, &hicn->protocol, &seq_number);
+ }
+
+ ctx = hicn_hs_get_ctx_by_index(ctx_index, thread_index);
+
+ if (PREDICT_FALSE(!ctx))
+ *error = HICN_HS_ERROR_WRONG_THREAD;
+
+ buffer->seq_number = seq_number;
+ buffer->is_ip4 = is_ip4;
+
+ return ctx;
+}
+
+static inline void
+hicn_hs_input_dispatch_buffer (hicn_hs_main_t * hm, hicn_hs_ctx_t * ctx,
+ vlib_buffer_t * b, u16 * next,
+ vlib_node_runtime_t * error_node)
+{
+ u32 error;
+ hicn_hs_buffer_t *buffer = hicn_hs_buffer (b);
+ *next = hm->dispatch_table[buffer->is_interest].next;
+ error = hm->dispatch_table[buffer->is_interest].error;
+ b->error = error_node->errors[error];
+}
+
+always_inline void
+hicn_hs_input_set_error_next (hicn_hs_main_t * tm, u16 * next, u32 * error, u8 is_ip4)
+{
+ *next = HICN_HS_INPUT_NEXT_DROP;
+}
+
+always_inline uword
+hicn_hs_input_inline (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame, u8 is_ip4)
+{
+ u32 n_left_from, *from, thread_index = vm->thread_index;
+ hicn_hs_main_t *hm = hicn_hs_get_main ();
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
+ u16 nexts[VLIB_FRAME_SIZE], *next;
+ vlib_node_runtime_t *error_node;
+
+// tcp_set_time_now (tcp_get_worker (thread_index));
+
+ error_node = vlib_node_get_runtime (vm, is_ip4 ? hicn_hs_input4_node.index : hicn_hs_input6_node.index);
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+ vlib_get_buffers (vm, from, bufs, n_left_from);
+
+ b = bufs;
+ next = nexts;
+
+ while (n_left_from >= 4)
+ {
+ u32 error0 = HICN_HS_ERROR_NO_CONTEXT, error1 = HICN_HS_ERROR_NO_CONTEXT;
+ hicn_hs_ctx_t *ctx0, *ctx1;
+
+ {
+ vlib_prefetch_buffer_header (b[2], STORE);
+ CLIB_PREFETCH (b[2]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+
+ vlib_prefetch_buffer_header (b[3], STORE);
+ CLIB_PREFETCH (b[3]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+
+ next[0] = next[1] = HICN_HS_INPUT_NEXT_DROP;
+
+ ctx0 = hicn_hs_input_lookup_buffer (b[0], thread_index, &error0, is_ip4);
+ ctx1 = hicn_hs_input_lookup_buffer (b[1], thread_index, &error1, is_ip4);
+
+ if (PREDICT_TRUE (!ctx0 + !ctx1 == 0))
+ {
+ hicn_hs_input_dispatch_buffer (hm, ctx0, b[0], &next[0], error_node);
+ hicn_hs_input_dispatch_buffer (hm, ctx1, b[1], &next[1], error_node);
+ }
+ else
+ {
+ if (PREDICT_TRUE (ctx0 != 0))
+ {
+ hicn_hs_input_dispatch_buffer (hm, ctx0, b[0], &next[0], error_node);
+ }
+ else
+ {
+ hicn_hs_input_set_error_next (hm, &next[0], &error0, is_ip4);
+ b[0]->error = error_node->errors[error0];
+ }
+
+ if (PREDICT_TRUE (ctx1 != 0))
+ {
+ hicn_hs_input_dispatch_buffer (hm, ctx1, b[1], &next[1], error_node);
+ }
+ else
+ {
+ hicn_hs_input_set_error_next (hm, &next[1], &error1, is_ip4);
+ b[1]->error = error_node->errors[error1];
+ }
+ }
+
+ b += 2;
+ next += 2;
+ n_left_from -= 2;
+ }
+ while (n_left_from > 0)
+ {
+ hicn_hs_ctx_t *ctx0;
+ u32 error0 = HICN_HS_ERROR_NO_CONTEXT;
+
+ if (n_left_from > 1)
+ {
+ vlib_prefetch_buffer_header (b[1], STORE);
+ CLIB_PREFETCH (b[1]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+
+ next[0] = HICN_HS_INPUT_NEXT_DROP;
+ ctx0 = hicn_hs_input_lookup_buffer (b[0], thread_index, &error0, is_ip4);
+ if (PREDICT_TRUE (ctx0 != 0))
+ {
+ hicn_hs_input_dispatch_buffer (hm, ctx0, b[0], &next[0], error_node);
+ }
+ else
+ {
+ hicn_hs_input_set_error_next (hm, &next[0], &error0, is_ip4);
+ b[0]->error = error_node->errors[error0];
+ }
+
+ b += 1;
+ next += 1;
+ n_left_from -= 1;
+ }
+
+ if (PREDICT_FALSE (node->flags & VLIB_NODE_FLAG_TRACE))
+ hicn_hs_input_trace_frame (vm, node, bufs, frame->n_vectors, is_ip4);
+
+ vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
+ return frame->n_vectors;
+}
+
+static uword
+hicn_hs_input_data (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ u32 n_left_from, *from, *first_buffer;
+ u32 thread_index = vm->thread_index;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
+ u32 node_index = hicn_hs_input_data_node.index;
+
+ from = first_buffer = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+ vlib_get_buffers (vm, from, bufs, n_left_from);
+
+ b = bufs;
+
+ hicn_hs_ctx_t *ctx0 = 0;
+
+ while (n_left_from >= 4)
+ {
+ u32 ctxi0, ctxi1;
+ hicn_hs_ctx_t *ctx1;
+
+ {
+ vlib_prefetch_buffer_header (b[2], STORE);
+ CLIB_PREFETCH (b[2]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+
+ vlib_prefetch_buffer_header (b[3], STORE);
+ CLIB_PREFETCH (b[3]->data, 2 * CLIB_CACHE_LINE_BYTES, LOAD);
+ }
+
+ // ctxi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
+ ctxi0 = hicn_hs_buffer (b[0])->ctx_index;
+ ctx0 = hicn_hs_get_ctx_by_index(ctxi0, thread_index);
+ // ctxi1 = vnet_buffer (b[1])->ip.adj_index[VLIB_TX];
+ ctxi1 = hicn_hs_buffer (b[1])->ctx_index;
+ ctx1 = hicn_hs_get_ctx_by_index(ctxi1, thread_index);
+
+ ASSERT (ctx0 && ctx1);
+
+ hicn_hs_process_incoming_data (ctx0, b[0]);
+ hicn_hs_process_incoming_data (ctx1, b[1]);
+
+ b += 2;
+ n_left_from -= 2;
+ }
+
+ while (n_left_from > 0)
+ {
+
+ u32 ctxi0;
+
+ // ctxi0 = vnet_buffer (b[0])->ip.adj_index[VLIB_TX];
+ ctxi0 = hicn_hs_buffer (b[0])->ctx_index;
+ ctx0 = hicn_hs_get_ctx_by_index(ctxi0, thread_index);
+
+ ASSERT (ctx0);
+
+ hicn_hs_process_incoming_data (ctx0, b[0]);
+
+ b += 1;
+ n_left_from -= 1;
+ }
+
+ hicn_hs_update_transport (ctx0, from_frame->n_vectors);
+
+// vlib_buffer_free (vm, first_buffer, from_frame->n_vectors);
+ vlib_node_increment_counter (vm, node_index, HICN_HS_ERROR_PACKETS_SENT, from_frame->n_vectors);
+ return from_frame->n_vectors;
+}
+
+static uword
+hicn_hs_input_interest (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * from_frame)
+{
+ u32 n_left_from, *from, *first_buffer;
+ u32 thread_index = vm->thread_index;
+ u32 ctx_index;
+
+ u32 node_index = hicn_hs_input_interest_node.index;
+
+ from = first_buffer = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+
+ while (n_left_from > 0)
+ {
+ u32 bi, CLIB_UNUSED(error) = HICN_HS_ERROR_NONE;
+ hicn_hs_ctx_t *ctx;
+ vlib_buffer_t *b;
+
+ bi = from[0];
+ from += 1;
+ n_left_from -= 1;
+
+ b = vlib_get_buffer (vm, bi);
+ ctx_index = vnet_buffer (b)->ip.adj_index[VLIB_TX];
+ ctx = hicn_hs_get_ctx_by_index(ctx_index, thread_index);
+ hicn_hs_process_incoming_interest(ctx, b);
+ }
+
+ vlib_node_increment_counter (vm, node_index, HICN_HS_ERROR_PACKETS_SENT, from_frame->n_vectors);
+ return from_frame->n_vectors;
+}
+
+static uword
+hicn_hs_input4 (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return hicn_hs_input_inline (vm, node, frame, 1);
+}
+
+static uword
+hicn_hs_input6 (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return hicn_hs_input_inline (vm, node, frame, 0);
+}
+
+/* *INDENT-OFF* */
+
+VLIB_REGISTER_NODE (hicn_hs_input_interest_node) =
+{
+ .function = hicn_hs_input_interest,
+ .name = HICN_HS_INPUT_INTEREST_NODE_NAME,
+ .vector_size = sizeof (u32),
+ .format_trace = format_hicn_hs_input_interest_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = HICN_HS_N_ERROR,
+ .error_strings = hicn_hs_error_strings,
+ .n_next_nodes = 0,
+};
+
+VLIB_REGISTER_NODE (hicn_hs_input_data_node) =
+{
+ .function = hicn_hs_input_data,
+ .name = HICN_HS_INPUT_DATA_NODE_NAME,
+ .vector_size = sizeof (u32),
+ .format_trace = format_hicn_hs_input_data_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = HICN_HS_N_ERROR,
+ .error_strings = hicn_hs_error_strings,
+ .n_next_nodes = 0,
+};
+
+VLIB_REGISTER_NODE (hicn_hs_input4_node) =
+{
+ .function = hicn_hs_input4,
+ .name = HICN_HS_INPUT4_NODE_NAME,
+ .vector_size = sizeof (u32),
+ .format_trace = format_hicn_hs_input4_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = HICN_HS_N_ERROR,
+ .error_strings = hicn_hs_error_strings,
+ .n_next_nodes = HICN_HS_INPUT_N_NEXT,
+ .next_nodes =
+ {
+#define _(s,n) [HICN_HS_INPUT_NEXT_##s] = n,
+ foreach_hicn_hs_input_next4
+#undef _
+ },
+};
+
+VLIB_REGISTER_NODE (hicn_hs_input6_node) =
+{
+ .function = hicn_hs_input6,
+ .name = HICN_HS_INPUT6_NODE_NAME,
+ .vector_size = sizeof (u32),
+ .format_trace = format_hicn_hs_input6_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = HICN_HS_N_ERROR,
+ .error_strings = hicn_hs_error_strings,
+ .n_next_nodes = HICN_HS_INPUT_N_NEXT,
+ .next_nodes =
+ {
+#define _(s,n) [HICN_HS_INPUT_NEXT_##s] = n,
+ foreach_hicn_hs_input_next6
+#undef _
+ },
+};
+
+/* *INDENT-ON* */
+
+static void
+hicn_hs_dispatch_table_init (hicn_hs_main_t * tm)
+{
+ int i;
+ for (i = 0; i < ARRAY_LEN (tm->dispatch_table); i++)
+ {
+ tm->dispatch_table[i].next = HICN_HS_INPUT_NEXT_DROP;
+ tm->dispatch_table[i].error = HICN_HS_ERROR_DISPATCH;
+ }
+
+#define _(t,n,e) \
+do { \
+ tm->dispatch_table[HICN_HS_##t].next = (n); \
+ tm->dispatch_table[HICN_HS_##t].error = (e); \
+} while (0)
+
+ _ (INTEREST, HICN_HS_INPUT_NEXT_INTEREST, HICN_HS_ERROR_NONE);
+ _ (DATA, HICN_HS_INPUT_NEXT_DATA, HICN_HS_ERROR_NONE);
+
+#undef _
+}
+
+static clib_error_t *
+hicn_hs_input_init (vlib_main_t * vm)
+{
+ hicn_hs_main_t *hm = hicn_hs_get_main ();
+
+ /* Initialize dispatch table. */
+ hicn_hs_dispatch_table_init (hm);
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (hicn_hs_input_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/host_stack/output_node.c b/hicn-plugin/src/host_stack/output_node.c
new file mode 100644
index 000000000..8e5f1e307
--- /dev/null
+++ b/hicn-plugin/src/host_stack/output_node.c
@@ -0,0 +1,287 @@
+/*
+ * 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 <vlibmemory/api.h>
+#include <vlib/vlib.h>
+
+#include "host_stack.h"
+#include "inlines.h"
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+#include <vppinfra/elog.h>
+
+#include <vnet/vnet.h>
+#include <vnet/pg/pg.h>
+#include <vnet/ip/ip.h>
+#include <vnet/udp/udp.h>
+#include <vnet/udp/udp_packet.h>
+#include <vnet/session/session.h>
+
+typedef enum _hicn_hs_output_next
+{
+ HICN_HS_OUTPUT_NEXT_IP_LOOKUP,
+ HICN_HS_OUTPUT_NEXT_NO_FLUSH,
+ HICN_HS_OUTPUT_N_NEXT
+} hicn_hs_output_next_t;
+
+/**
+ * Next nodes.
+ */
+#define foreach_hicn_hs_output4_next \
+ _ (IP_LOOKUP, "ip4-lookup") \
+ _ (NO_FLUSH, "hicn_hs-no-flush")
+// _ (DROP, "ip4-drop")
+
+
+#define foreach_hicn_hs_output6_next \
+ _ (IP_LOOKUP, "ip6-lookup") \
+ _ (NO_FLUSH, "hicn_hs-no-flush")
+// _ (DROP, "ip6-drop")
+
+
+typedef enum
+{
+#define _(s, n) HICN_HS_OUTPUT4_NEXT_##s,
+ foreach_hicn_hs_output4_next
+#undef _
+ HICN_HS_OUTPUT4_N_NEXT,
+} hicn_hs_output4_next_t;
+
+typedef enum
+{
+#define _(s, n) HICN_HS_OUTPUT6_NEXT_##s,
+ foreach_hicn_hs_output6_next
+#undef _
+ HICN_HS_OUTPUT6_N_NEXT,
+} hicn_hs_output6_next_t;
+
+typedef struct
+{
+ u32 next_index;
+ hicn_name_t name;
+} hicn_hs_output_trace_t;
+
+always_inline u8 *
+format_hicn_hs_output_trace_i (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ hicn_hs_output_trace_t *t = va_arg (*args, hicn_hs_output_trace_t *);
+ char name[64];
+ u32 indent = format_get_indent (s);
+
+ hicn_name_ntop(&t->name, name, 64);
+ s = format (s, "hicn_hs_output: next-index %d", t->next_index);
+ s = format (s, "\n%Upacket: name %s", format_white_space, indent + 2,
+ name);
+ return s;
+}
+
+static u8 *
+format_hicn_hs_output4_trace (u8 * s, va_list * args)
+{
+ return format_hicn_hs_output_trace_i(s, args);
+}
+
+static u8 *
+format_hicn_hs_output6_trace (u8 * s, va_list * args)
+{
+ return format_hicn_hs_output_trace_i(s, args);
+}
+
+static_always_inline void
+hicn_hs_trace_buffer (vlib_main_t * vm, vlib_node_runtime_t * node,
+ vlib_buffer_t * b, u32 next, uword * n_tracep)
+{
+ VLIB_BUFFER_TRACE_TRAJECTORY_INIT (b);
+
+ if (PREDICT_TRUE (b != 0))
+ {
+ hicn_hs_output_trace_t *tr;
+ vlib_trace_buffer (vm, node, next, b, /* follow_chain */ 0);
+ vlib_set_trace_count (vm, node, --(*n_tracep));
+ tr = vlib_add_trace (vm, node, b, sizeof (*tr));
+ tr->next_index = next;
+// hicn_interest_get_name(HF_INET6_TCP,
+// (const hicn_header_t *)vlib_buffer_get_current(b),
+// &tr->name);
+ }
+}
+
+always_inline uword
+hicn_hs_output_inline (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame, int is_ip4)
+{
+ u32 n_left_from, *from, thread_index = vm->thread_index;
+ vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
+ u16 nexts[VLIB_FRAME_SIZE], *next;
+
+ uword n_trace = vlib_get_trace_count (vm, node);
+
+ u32 node_index = is_ip4 ? hicn_hs_output4_node.index : hicn_hs_output6_node.index;
+
+ from = vlib_frame_vector_args (frame);
+ n_left_from = frame->n_vectors;
+
+ vlib_get_buffers (vm, from, bufs, n_left_from);
+ b = bufs;
+ next = nexts;
+
+ while (n_left_from >= 4)
+ {
+ hicn_hs_ctx_t *hc0, *hc1;
+ u8 flush0, flush1;
+
+ {
+ vlib_prefetch_buffer_header (b[2], STORE);
+ CLIB_PREFETCH (b[2]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+
+ vlib_prefetch_buffer_header (b[3], STORE);
+ CLIB_PREFETCH (b[3]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ hc0 = hicn_hs_get_ctx_by_index (hicn_hs_buffer (b[0])->ctx_index, thread_index);
+ hc1 = hicn_hs_get_ctx_by_index (hicn_hs_buffer (b[1])->ctx_index, thread_index);
+ flush0 = hicn_hs_buffer(b[0])->flush;
+ flush1 = hicn_hs_buffer(b[1])->flush;
+
+ ASSERT (hc0 && hc1);
+
+ vnet_buffer (b[0])->sw_if_index[VLIB_TX] = hc0->c_fib_index;
+ vnet_buffer (b[0])->sw_if_index[VLIB_RX] = 0;
+ next[0] = !flush0;
+
+ vnet_buffer (b[1])->sw_if_index[VLIB_TX] = hc1->c_fib_index;
+ vnet_buffer (b[1])->sw_if_index[VLIB_RX] = 0;
+ next[1] = !flush1;
+
+ if (PREDICT_FALSE (n_trace > 0))
+ {
+ hicn_hs_trace_buffer (vm, node, b[0], next[0], &n_trace);
+ if (PREDICT_FALSE (n_trace > 0))
+ hicn_hs_trace_buffer (vm, node, b[1], next[1], &n_trace);
+ }
+
+ b += 2;
+ n_left_from -= 2;
+ next += 2;
+ }
+ while (n_left_from > 0)
+ {
+ hicn_hs_ctx_t *hc0;
+ u8 flush0;
+
+ if (n_left_from > 1)
+ {
+ vlib_prefetch_buffer_header (b[1], STORE);
+ CLIB_PREFETCH (b[1]->data, 2 * CLIB_CACHE_LINE_BYTES, STORE);
+ }
+
+ hc0 = hicn_hs_get_ctx_by_index (hicn_hs_buffer (b[0])->ctx_index, thread_index);
+ flush0 = hicn_hs_buffer(b[0])->flush;
+
+ ASSERT (hc0);
+
+ vnet_buffer (b[0])->sw_if_index[VLIB_TX] = hc0->c_fib_index;
+ vnet_buffer (b[0])->sw_if_index[VLIB_RX] = 0;
+ next[0] = !flush0;
+
+ if (PREDICT_FALSE (n_trace > 0))
+ hicn_hs_trace_buffer (vm, node, b[0], next[0], &n_trace);
+
+ b += 1;
+ n_left_from -= 1;
+ next += 1;
+ }
+
+ vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
+ vlib_node_increment_counter (vm, node_index, HICN_HS_ERROR_PACKETS_SENT, frame->n_vectors);
+
+ return frame->n_vectors;
+}
+
+static uword
+hicn_hs_output4_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return hicn_hs_output_inline (vm, node, frame, 1);
+}
+
+static uword
+hicn_hs_output6_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return hicn_hs_output_inline (vm, node, frame, 0);
+}
+
+static uword
+hicn_hs_no_flush_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node,
+ vlib_frame_t * frame)
+{
+ return frame->n_vectors;
+}
+
+VLIB_REGISTER_NODE (hicn_hs_no_flush_node) = {
+ .function = hicn_hs_no_flush_node_fn,
+ .name = "hicn_hs-no-flush",
+ .vector_size = sizeof (u32),
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = HICN_HS_N_ERROR,
+ .error_strings = hicn_hs_error_strings,
+ .n_next_nodes = 0,
+ .next_nodes = {},
+};
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (hicn_hs_output4_node) = {
+ .function = hicn_hs_output4_node_fn,
+ .name = HICN_HS_OUTPUT4_NODE_NAME,
+ .vector_size = sizeof (u32),
+ .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
+ .format_trace = format_hicn_hs_output4_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = HICN_HS_N_ERROR,
+ .error_strings = hicn_hs_error_strings,
+ .n_next_nodes = HICN_HS_OUTPUT4_N_NEXT,
+ .next_nodes = {
+#define _(s, n) [HICN_HS_OUTPUT4_NEXT_##s] = n,
+ foreach_hicn_hs_output4_next
+#undef _
+ },
+};
+
+VLIB_REGISTER_NODE (hicn_hs_output6_node) = {
+ .function = hicn_hs_output6_node_fn,
+ .name = HICN_HS_OUTPUT6_NODE_NAME,
+ .vector_size = sizeof (u32),
+ .flags = VLIB_NODE_FLAG_TRACE_SUPPORTED,
+ .format_trace = format_hicn_hs_output6_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+ .n_errors = HICN_HS_N_ERROR,
+ .error_strings = hicn_hs_error_strings,
+ .n_next_nodes = HICN_HS_OUTPUT6_N_NEXT,
+ .next_nodes = {
+#define _(s, n) [HICN_HS_OUTPUT6_NEXT_##s] = n,
+ foreach_hicn_hs_output6_next
+#undef _
+ },
+};
+
+/* *INDENT-ON* */ \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/producer_dpo.c b/hicn-plugin/src/host_stack/producer_dpo.c
new file mode 100644
index 000000000..c7b77705d
--- /dev/null
+++ b/hicn-plugin/src/host_stack/producer_dpo.c
@@ -0,0 +1,90 @@
+/*
+ * 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 "producer_dpo.h"
+#include "host_stack.h"
+
+#include <vnet/ip/format.h>
+#include <vnet/adj/adj.h>
+#include <vnet/vnet.h>
+#include <vlib/vlib.h>
+
+dpo_type_t hicn_hs_dpo_type;
+
+const static char *const hicn_hs_prod_dpo4_nodes[] = {
+ "hicn_hs-input4",
+ NULL,
+};
+
+const static char *const hicn_hs_prod_dpo6_nodes[] = {
+ "hicn_hs-input6",
+ NULL,
+};
+
+const static char *const *const hicn_hs_prod_dpo_nodes[DPO_PROTO_NUM] = {
+ [DPO_PROTO_IP4] = hicn_hs_prod_dpo4_nodes,
+ [DPO_PROTO_IP6] = hicn_hs_prod_dpo6_nodes
+};
+
+void hicn_hs_prod_dpo_lock(dpo_id_t *dpo)
+{
+ return;
+}
+
+void hicn_hs_prod_dpo_unlock(dpo_id_t *dpo)
+{
+ return;
+}
+
+u8 *format_hicn_hs_prod_dpo (u8 * s, va_list * args)
+{
+ return s;
+}
+
+const static dpo_vft_t hicn_hs_prod_dpo_vft = {
+ .dv_lock = hicn_hs_prod_dpo_lock,
+ .dv_unlock = hicn_hs_prod_dpo_unlock,
+ .dv_format = format_hicn_hs_prod_dpo,
+};
+
+/**
+ * Register the new DPO type.
+ */
+void hicn_hs_dpo_module_init(void)
+{
+ hicn_hs_dpo_type = dpo_register_new_type (&hicn_hs_prod_dpo_vft, hicn_hs_prod_dpo_nodes);
+}
+
+int dpo_is_hicn_hs(const dpo_id_t *dpo)
+{
+ return dpo->dpoi_type == hicn_hs_dpo_type;
+}
+
+u32 hicn_hs_dpo_create(u32 hicn_hs_ctx_idx, u8 is_ip4, dpo_id_t *dpo)
+{
+ dpo->dpoi_type = DPO_FIRST;
+ dpo->dpoi_proto = DPO_PROTO_NONE;
+ dpo->dpoi_index = INDEX_INVALID;
+ dpo->dpoi_next_node = 0;
+
+ u16 next_node = is_ip4 ? hicn_hs_input4_node.index : hicn_hs_input6_node.index;
+
+ index_t dpoi_index = hicn_hs_ctx_idx;
+ dpo_set(dpo, hicn_hs_dpo_type, is_ip4 ? DPO_PROTO_IP4 : DPO_PROTO_IP6, dpoi_index);
+ dpo->dpoi_next_node = next_node;
+ dpo_unlock (dpo);
+
+ return HICN_HS_ERROR_NONE;
+}
diff --git a/hicn-plugin/src/host_stack/producer_dpo.h b/hicn-plugin/src/host_stack/producer_dpo.h
new file mode 100644
index 000000000..ac748589b
--- /dev/null
+++ b/hicn-plugin/src/host_stack/producer_dpo.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/**
+ * @brief The hicn_hs dpo. It will store the 2 hicn_hs input nodes,
+ * altogether with the index of the corresponding hicn socket, in order
+ * to avoid a double lookup.
+ */
+
+#ifndef __HICN_HS_DPO_H__
+#define __HICN_HS_DPO_H__
+
+#include <vnet/dpo/dpo.h>
+
+extern dpo_type_t hicn_hs_dpo_type;
+
+int dpo_is_hicn_hs(const dpo_id_t *dpo);
+u32 hicn_hs_dpo_create(u32 hicn_hs_ctx_idx, u8 is_ip4, dpo_id_t *dpo);
+void hicn_hs_dpo_module_init(void);
+
+#endif /* __HICN_HS_DPO_H__ */ \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/proto.h b/hicn-plugin/src/host_stack/proto.h
new file mode 100644
index 000000000..0c89317a6
--- /dev/null
+++ b/hicn-plugin/src/host_stack/proto.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 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 __included_hicn_hs_proto__
+#define __included_hicn_hs_proto__
+
+#define PROTO_DATA_SIZE 32
+
+typedef enum hicn_hs_proto_event_
+{
+ PROTO_N_EVENT,
+} hicn_hs_proto_event_t;
+
+struct hicn_hs_proto_
+{
+ u32 (*init) (hicn_hs_ctx_t * hc);
+ u32 (*rcv_data) (hicn_hs_ctx_t * hc);
+ u32 (*rcv_interest) (hicn_hs_ctx_t * hc);
+ u32 (*on_interest_timeout) (hicn_hs_ctx_t *hc);
+ u32 (*event) (hicn_hs_ctx_t *hc, hicn_hs_proto_event_t event);
+ u32 (*next_seq_number) (hicn_hs_ctx_t *hc);
+ u8 proto_data[PROTO_DATA_SIZE];
+};
+
+typedef struct hicn_hs_proto_ hicn_hs_proto_t;
+
+always_inline void *
+hicn_hs_proto_data(hicn_hs_proto_t *proto)
+{
+ return (void*)(proto->proto_data);
+}
+
+always_inline u32
+hicn_hs_proto_init ();
+
+#enfif /* __included_hicn_hs_proto__ */ \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/route.c b/hicn-plugin/src/host_stack/route.c
new file mode 100644
index 000000000..5b42bea26
--- /dev/null
+++ b/hicn-plugin/src/host_stack/route.c
@@ -0,0 +1,178 @@
+/*
+ * 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 "host_stack.h"
+#include "route.h"
+
+#include <vnet/fib/fib_entry.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/ip/ip6_packet.h>
+#include <vnet/dpo/dpo.h>
+#include <vnet/dpo/load_balance.h>
+#include <vlib/global_funcs.h>
+#include <vnet/dpo/drop_dpo.h>
+
+#define FIB_SOURCE_HICN_HS 0x04 //Right after the FIB_SOURCE_INTERFACE priority
+#define HICN_HS_FIB_TABLE 0
+
+fib_source_t hicn_hs_fib_src;
+
+void
+hicn_hs_route_init ()
+{
+ hicn_hs_fib_src = fib_source_allocate ("hicn_hs", FIB_SOURCE_HICN_HS, FIB_SOURCE_BH_API);
+}
+
+always_inline int
+hicn_route_get_dpo (const fib_prefix_t * prefix,
+ const dpo_id_t ** hicn_dpo, u32 * fib_index)
+{
+ //fib_prefix_t fib_pfx;
+ const dpo_id_t *load_balance_dpo_id;
+ const dpo_id_t *former_dpo_id;
+ int found = 0, ret = HICN_HS_ERROR_ROUTE_NOT_FOUND;
+ fib_node_index_t fib_entry_index;
+
+ /* Check if the route already exist in the fib */
+ /*
+ * ASSUMPTION: we use table 0 which is the default table and it is
+ * already existing and locked
+ */
+ *fib_index = fib_table_find_or_create_and_lock (prefix->fp_proto,
+ HICN_HS_FIB_TABLE,
+ hicn_hs_fib_src);
+ fib_entry_index = fib_table_lookup_exact_match (*fib_index, prefix);
+
+ if (fib_entry_index != FIB_NODE_INDEX_INVALID)
+ {
+ /* Route already existing. We need to update the dpo. */
+ load_balance_dpo_id =
+ fib_entry_contribute_ip_forwarding (fib_entry_index);
+
+ /* The dpo is not a load balance dpo as expected */
+ if (load_balance_dpo_id->dpoi_type != DPO_LOAD_BALANCE)
+ ret = HICN_HS_ERROR_ROUTE_NO_LB_DPO;
+ else
+ {
+ /* former_dpo_id is a load_balance dpo */
+ load_balance_t *lb =
+ load_balance_get (load_balance_dpo_id->dpoi_index);
+
+ /* FIB entry exists but there is no hicn_hs dpo. */
+ ret = HICN_HS_ERROR_ROUTE_DPO_NO_HICN;
+ for (int i = 0; i < lb->lb_n_buckets && !found; i++)
+ {
+ former_dpo_id = load_balance_get_bucket_i (lb, i);
+
+ if (dpo_is_hicn_hs (former_dpo_id))
+ {
+ *hicn_dpo = former_dpo_id;
+ ret = HICN_HS_ERROR_NONE;
+ found = 1;
+ }
+ }
+ }
+ }
+ /*
+ * Remove the lock from the table. We keep one lock per route, not
+ * per dpo
+ */
+ fib_table_unlock (*fib_index, prefix->fp_proto, hicn_hs_fib_src);
+
+ return ret;
+}
+
+/* Add a new route for a name prefix */
+always_inline
+int hicn_hs_route_add_flags (const fib_prefix_t * prefix, const dpo_id_t *dpo, fib_entry_flag_t flags)
+{
+ CLIB_UNUSED(vlib_main_t *vm) = vlib_get_main ();
+ int ret = HICN_HS_ERROR_NONE;
+ u32 fib_index;
+ const dpo_id_t *_dpo;
+
+ ret = hicn_route_get_dpo (prefix, &_dpo, &fib_index);
+
+ if (ret == HICN_HS_ERROR_ROUTE_NOT_FOUND)
+ {
+ /* Here is where we create the "via" like route */
+ /*
+ * For the moment we use the global one the prefix you want
+ * to match Neale suggested -- FIB_SOURCE_HICN the client
+ * that is adding them -- no easy explanation at this time…
+ */
+ fib_node_index_t new_fib_node_index =
+ fib_table_entry_special_dpo_add (fib_index,
+ prefix,
+ hicn_hs_fib_src,
+ flags,
+ dpo);
+
+ /* We added a route, therefore add one lock to the table */
+ fib_table_lock (fib_index, prefix->fp_proto, hicn_hs_fib_src);
+
+ ret =
+ (new_fib_node_index !=
+ FIB_NODE_INDEX_INVALID) ? HICN_HS_ERROR_NONE :
+ HICN_HS_ERROR_ROUTE_NO_INSERT;
+ }
+
+ return ret;
+}
+
+int
+hicn_hs_route_add (const fib_prefix_t * prefix, const dpo_id_t *dpo)
+{
+ return hicn_hs_route_add_flags(prefix, dpo, (FIB_ENTRY_FLAG_EXCLUSIVE |
+ FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
+}
+
+clib_error_t *
+hicn_hs_set_local_prefix(const fib_prefix_t * prefix)
+{
+ clib_error_t * ret = 0;
+ int rv;
+ const dpo_id_t *drop_dpo = drop_dpo_get(prefix->fp_proto == FIB_PROTOCOL_IP4 ? DPO_PROTO_IP4 : DPO_PROTO_IP6);
+ rv = hicn_hs_route_add_flags(prefix, drop_dpo, (FIB_ENTRY_FLAG_EXCLUSIVE | FIB_ENTRY_FLAG_LOCAL | FIB_ENTRY_FLAG_LOOSE_URPF_EXEMPT));
+
+ if (rv)
+ ret = clib_error_return (0, "Error: %s", hicn_hs_error_strings[rv]);
+
+ return ret;
+}
+
+int
+hicn_route_del (fib_prefix_t * prefix)
+{
+ const dpo_id_t *hicn_dpo_id;
+ int ret = HICN_HS_ERROR_NONE;
+ u32 fib_index;
+
+ /* Remove the fib entry only if the dpo is of type hicn */
+ ret = hicn_route_get_dpo (prefix, &hicn_dpo_id, &fib_index);
+
+ if (ret == HICN_HS_ERROR_NONE)
+ {
+ fib_table_entry_special_remove (HICN_HS_FIB_TABLE, prefix, hicn_hs_fib_src);
+
+ /*
+ * Remove the lock from the table. We keep one lock per route
+ */
+ fib_table_unlock (fib_index, prefix->fp_proto, hicn_hs_fib_src);
+ }
+
+ // Remember to remove the lock from the table when removing the entry
+ return ret;
+} \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/route.h b/hicn-plugin/src/host_stack/route.h
new file mode 100644
index 000000000..880a34687
--- /dev/null
+++ b/hicn-plugin/src/host_stack/route.h
@@ -0,0 +1,37 @@
+/*
+ * 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 __HICN_HS_ROUTE_H__
+#define __HICN_HS_ROUTE_H__
+
+#include <vnet/fib/fib.h>
+#include <vnet/dpo/dpo.h>
+
+/* Init the route module */
+void
+hicn_hs_route_init ();
+
+clib_error_t *
+hicn_hs_set_local_prefix(const fib_prefix_t * prefix);
+
+/* Add a new route for a name prefix */
+int
+hicn_hs_route_add (const fib_prefix_t * prefix, const dpo_id_t *dpo);
+
+/* Remove route for a name prefix */
+int
+hicn_route_del (fib_prefix_t * prefix);
+
+#endif /* __HICN_HS_ROUTE_H__ */
diff --git a/hicn-plugin/src/host_stack/test/hicn_hs_client.c b/hicn-plugin/src/host_stack/test/hicn_hs_client.c
new file mode 100644
index 000000000..b5f27ee12
--- /dev/null
+++ b/hicn-plugin/src/host_stack/test/hicn_hs_client.c
@@ -0,0 +1,804 @@
+/*
+ * hicn_hs_client.c - vpp built-in hicn client
+ *
+ * Copyright (c) 2017-2019 by 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 <vnet/vnet.h>
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+#include "hicn_hs_client.h"
+#include "../host_stack.h"
+
+hicn_client_main_t hicn_client_main;
+
+#define HICN_CLIENT_DBG (0)
+#define DBG(_fmt, _args...) \
+ if (HICN_CLIENT_DBG) \
+ clib_warning (_fmt, ##_args)
+
+#define ec_cli_output(_fmt, _args...) \
+ if (!hcm->no_output) \
+ vlib_cli_output(vm, _fmt, ##_args)
+
+f64 t0;
+
+static void
+signal_evt_to_cli_i (int *code)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ ASSERT (vlib_get_thread_index () == 0);
+ vlib_process_signal_event (hcm->vlib_main, hcm->cli_node_index, *code, 0);
+}
+
+static void
+signal_evt_to_cli (int code)
+{
+ if (vlib_get_thread_index () != 0)
+ vl_api_rpc_call_main_thread (signal_evt_to_cli_i, (u8 *) & code,
+ sizeof (code));
+ else
+ signal_evt_to_cli_i (&code);
+}
+
+static void
+receive_data_chunk (hicn_client_main_t * hcm, eclient_session_t * s)
+{
+ svm_fifo_t *rx_fifo = s->data.rx_fifo;
+ u32 thread_index = vlib_get_thread_index ();
+ int n_read, i;
+
+ if (hcm->test_bytes)
+ {
+ if (!hcm->is_dgram)
+ n_read = app_recv_stream (&s->data, hcm->rx_buf[thread_index],
+ vec_len (hcm->rx_buf[thread_index]));
+ else
+ n_read = app_recv_dgram (&s->data, hcm->rx_buf[thread_index],
+ vec_len (hcm->rx_buf[thread_index]));
+ }
+ else
+ {
+ n_read = svm_fifo_max_dequeue_cons (rx_fifo);
+ svm_fifo_dequeue_drop (rx_fifo, n_read);
+ }
+
+ if (n_read > 0)
+ {
+ if (HICN_CLIENT_DBG)
+ {
+ /* *INDENT-OFF* */
+ ELOG_TYPE_DECLARE (e) =
+ {
+ .format = "rx-deq: %d bytes",
+ .format_args = "i4",
+ };
+ /* *INDENT-ON* */
+ struct
+ {
+ u32 data[1];
+ } *ed;
+ ed = ELOG_DATA (&vlib_global_main.elog_main, e);
+ ed->data[0] = n_read;
+ }
+
+ if (hcm->test_bytes)
+ {
+ for (i = 0; i < n_read; i++)
+ {
+ if (hcm->rx_buf[thread_index][i]
+ != ((s->bytes_received + i) & 0xff))
+ {
+ clib_warning ("read %d error at byte %lld, 0x%x not 0x%x",
+ n_read, s->bytes_received + i,
+ hcm->rx_buf[thread_index][i],
+ ((s->bytes_received + i) & 0xff));
+ hcm->test_failed = 1;
+ }
+ }
+ }
+ vlib_main_t *vm = vlib_get_main();
+ hcm->test_end_time = vlib_time_now (vm);
+ f64 delta = hcm->test_end_time - hcm->test_start_time;
+
+ ec_cli_output ("Throughput (%d, %.20f): %.2f b/s", n_read, delta, ((f64)(n_read)) / delta);
+
+ s->bytes_to_receive -= n_read;
+ s->bytes_received += n_read;
+ }
+}
+
+// static uword
+// hicn_client_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
+// vlib_frame_t * frame)
+// {
+// hicns_client_main_t *hcm = &hicn_client_main;
+// int my_thread_index = vlib_get_thread_index ();
+// eclient_session_t *sp;
+// int i;
+// int delete_session;
+// u32 *connection_indices;
+// u32 *connections_this_batch;
+// u32 nconnections_this_batch;
+
+// connection_indices = hcm->connection_index_by_thread[my_thread_index];
+// connections_this_batch =
+// hcm->connections_this_batch_by_thread[my_thread_index];
+
+// if ((hcm->run_test != HICN_CLIENT_RUNNING) ||
+// ((vec_len (connection_indices) == 0)
+// && vec_len (connections_this_batch) == 0))
+// return 0;
+
+// /* Grab another pile of connections */
+// if (PREDICT_FALSE (vec_len (connections_this_batch) == 0))
+// {
+// nconnections_this_batch =
+// clib_min (hcm->connections_per_batch, vec_len (connection_indices));
+
+// ASSERT (nconnections_this_batch > 0);
+// vec_validate (connections_this_batch, nconnections_this_batch - 1);
+// clib_memcpy_fast (connections_this_batch,
+// connection_indices + vec_len (connection_indices)
+// - nconnections_this_batch,
+// nconnections_this_batch * sizeof (u32));
+// _vec_len (connection_indices) -= nconnections_this_batch;
+// }
+
+// if (PREDICT_FALSE (hcm->prev_conns != hcm->connections_per_batch
+// && hcm->prev_conns == vec_len (connections_this_batch)))
+// {
+// hcm->repeats++;
+// hcm->prev_conns = vec_len (connections_this_batch);
+// if (hcm->repeats == 500000)
+// {
+// clib_warning ("stuck clients");
+// }
+// }
+// else
+// {
+// hcm->prev_conns = vec_len (connections_this_batch);
+// hcm->repeats = 0;
+// }
+
+// for (i = 0; i < vec_len (connections_this_batch); i++)
+// {
+// delete_session = 1;
+
+// sp = pool_elt_at_index (hcm->sessions, connections_this_batch[i]);
+
+// if (sp->bytes_to_send > 0)
+// {
+// send_data_chunk (hcm, sp);
+// delete_session = 0;
+// }
+// if (sp->bytes_to_receive > 0)
+// {
+// delete_session = 0;
+// }
+// if (PREDICT_FALSE (delete_session == 1))
+// {
+// session_t *s;
+
+// clib_atomic_fetch_add (&hcm->tx_total, sp->bytes_sent);
+// clib_atomic_fetch_add (&hcm->rx_total, sp->bytes_received);
+// s = session_get_from_handle_if_valid (sp->vpp_session_handle);
+
+// if (s)
+// {
+// vnet_disconnect_args_t _a, *a = &_a;
+// a->handle = session_handle (s);
+// a->app_index = hcm->app_index;
+// vnet_disconnect_session (a);
+
+// vec_delete (connections_this_batch, 1, i);
+// i--;
+// clib_atomic_fetch_add (&hcm->ready_connections, -1);
+// }
+// else
+// {
+// clib_warning ("session AWOL?");
+// vec_delete (connections_this_batch, 1, i);
+// }
+
+// /* Kick the debug CLI process */
+// if (hcm->ready_connections == 0)
+// {
+// signal_evt_to_cli (2);
+// }
+// }
+// }
+
+// hcm->connection_index_by_thread[my_thread_index] = connection_indices;
+// hcm->connections_this_batch_by_thread[my_thread_index] =
+// connections_this_batch;
+// return 0;
+// }
+
+// /* *INDENT-OFF* */
+// VLIB_REGISTER_NODE (hicn_clients_node) =
+// {
+// .function = hicn_client_node_fn,
+// .name = "hicn-client",
+// .type = VLIB_NODE_TYPE_INPUT,
+// .state = VLIB_NODE_STATE_DISABLED,
+// };
+// /* *INDENT-ON* */
+
+static int
+create_api_loopback (hicn_client_main_t * hcm)
+{
+ api_main_t *am = vlibapi_get_main ();
+ vl_shmem_hdr_t *shmem_hdr;
+
+ shmem_hdr = am->shmem_hdr;
+ hcm->vl_input_queue = shmem_hdr->vl_input_queue;
+ hcm->my_client_index = vl_api_memclnt_create_internal ("hicn_client",
+ hcm->vl_input_queue);
+ return 0;
+}
+
+static int
+hicn_client_init (vlib_main_t * vm)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vlib_thread_main_t *vtm = vlib_get_thread_main ();
+ u32 num_threads;
+ int i;
+
+ if (create_api_loopback (hcm))
+ return -1;
+
+ num_threads = 1 /* main thread */ + vtm->n_threads;
+
+ /* Init test data. Big buffer */
+ vec_validate (hcm->connect_test_data, 4 * 1024 * 1024 - 1);
+ for (i = 0; i < vec_len (hcm->connect_test_data); i++)
+ hcm->connect_test_data[i] = i & 0xff;
+
+ vec_validate (hcm->rx_buf, num_threads - 1);
+ for (i = 0; i < num_threads; i++)
+ vec_validate (hcm->rx_buf[i], vec_len (hcm->connect_test_data) - 1);
+
+ hcm->is_init = 1;
+
+ vec_validate (hcm->connection_index_by_thread, vtm->n_vlib_mains);
+ vec_validate (hcm->connections_this_batch_by_thread, vtm->n_vlib_mains);
+ vec_validate (hcm->vpp_event_queue, vtm->n_vlib_mains);
+
+ return 0;
+}
+
+static int
+hicn_client_session_connected_callback (u32 app_wrk_index, u32 opaque,
+ session_t * s, session_error_t code)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ eclient_session_t *session;
+ u32 session_index;
+ u8 thread_index;
+
+ if (PREDICT_FALSE (hcm->run_test != HICN_CLIENT_STARTING))
+ return -1;
+
+ if (code)
+ {
+ clib_warning ("connection %d failed!", opaque);
+ hcm->run_test = HICN_CLIENT_EXITING;
+ signal_evt_to_cli (-1);
+ return 0;
+ }
+
+ thread_index = s->thread_index;
+ ASSERT (thread_index == vlib_get_thread_index ()
+ || session_transport_service_type (s) == TRANSPORT_SERVICE_CL);
+
+ if (!hcm->vpp_event_queue[thread_index])
+ hcm->vpp_event_queue[thread_index] =
+ session_main_get_vpp_event_queue (thread_index);
+
+ /*
+ * Setup session
+ */
+ clib_spinlock_lock_if_init (&hcm->sessions_lock);
+ pool_get (hcm->sessions, session);
+ clib_spinlock_unlock_if_init (&hcm->sessions_lock);
+
+ clib_memset (session, 0, sizeof (*session));
+ session_index = session - hcm->sessions;
+ session->bytes_to_send = hcm->bytes_to_send;
+ session->bytes_to_receive = hcm->no_return ? 0ULL : hcm->bytes_to_send;
+ session->data.rx_fifo = s->rx_fifo;
+ session->data.rx_fifo->client_session_index = session_index;
+ session->data.tx_fifo = s->tx_fifo;
+ session->data.tx_fifo->client_session_index = session_index;
+ session->data.vpp_evt_q = hcm->vpp_event_queue[thread_index];
+ session->vpp_session_handle = session_handle (s);
+
+ if (hcm->is_dgram)
+ {
+ transport_connection_t *tc;
+ tc = session_get_transport (s);
+ clib_memcpy_fast (&session->data.transport, tc,
+ sizeof (session->data.transport));
+ session->data.is_dgram = 1;
+ }
+
+ vec_add1 (hcm->connection_index_by_thread[thread_index], session_index);
+ clib_atomic_fetch_add (&hcm->ready_connections, 1);
+ if (hcm->ready_connections == hcm->expected_connections)
+ {
+ hcm->run_test = HICN_CLIENT_RUNNING;
+ /* Signal the CLI process that the action is starting... */
+ signal_evt_to_cli (1);
+ }
+
+ return 0;
+}
+
+static void
+hicn_client_session_reset_callback (session_t * s)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+
+ if (s->session_state == SESSION_STATE_READY)
+ clib_warning ("Reset active connection %U", format_session, s, 2);
+
+ a->handle = session_handle (s);
+ a->app_index = hcm->app_index;
+ vnet_disconnect_session (a);
+ return;
+}
+
+static int
+hicn_client_session_create_callback (session_t * s)
+{
+ return 0;
+}
+
+static void
+hicn_client_session_disconnect_callback (session_t * s)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+ a->handle = session_handle (s);
+ a->app_index = hcm->app_index;
+ vnet_disconnect_session (a);
+ return;
+}
+
+void
+hicn_client_session_disconnect (session_t * s)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+ a->handle = session_handle (s);
+ a->app_index = hcm->app_index;
+ vnet_disconnect_session (a);
+}
+
+static int
+hicn_client_rx_callback (session_t * s)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ eclient_session_t *sp;
+
+ if (PREDICT_FALSE (hcm->run_test != HICN_CLIENT_RUNNING))
+ {
+ hicn_client_session_disconnect (s);
+ return -1;
+ }
+
+ sp = pool_elt_at_index (hcm->sessions, s->rx_fifo->client_session_index);
+ receive_data_chunk (hcm, sp);
+
+ if (svm_fifo_max_dequeue_cons (s->rx_fifo))
+ {
+ if (svm_fifo_set_event (s->rx_fifo))
+ session_send_io_evt_to_thread (s->rx_fifo, SESSION_IO_EVT_BUILTIN_RX);
+ }
+ return 0;
+}
+
+int
+hicn_client_add_segment_callback (u32 client_index, u64 segment_handle)
+{
+ /* New heaps may be added */
+ return 0;
+}
+
+/* *INDENT-OFF* */
+static session_cb_vft_t hicn_client = {
+ .session_reset_callback = hicn_client_session_reset_callback,
+ .session_connected_callback = hicn_client_session_connected_callback,
+ .session_accept_callback = hicn_client_session_create_callback,
+ .session_disconnect_callback = hicn_client_session_disconnect_callback,
+ .builtin_app_rx_callback = hicn_client_rx_callback,
+ .add_segment_callback = hicn_client_add_segment_callback
+};
+/* *INDENT-ON* */
+
+static clib_error_t *
+hicn_client_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
+{
+ vnet_app_add_tls_cert_args_t _a_cert, *a_cert = &_a_cert;
+ vnet_app_add_tls_key_args_t _a_key, *a_key = &_a_key;
+ u32 prealloc_fifos, segment_size = 256 << 20;
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vnet_app_attach_args_t _a, *a = &_a;
+ u64 options[17];
+ int rv;
+
+ clib_memset (a, 0, sizeof (*a));
+ clib_memset (options, 0, sizeof (options));
+
+ a->api_client_index = hcm->my_client_index;
+ a->session_cb_vft = &hicn_client;
+
+ prealloc_fifos = hcm->prealloc_fifos ? hcm->expected_connections : 1;
+
+ if (hcm->private_segment_size)
+ segment_size = hcm->private_segment_size;
+
+ options[APP_OPTIONS_ACCEPT_COOKIE] = 0x12345678;
+ options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
+ options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
+ options[APP_OPTIONS_RX_FIFO_SIZE] = hcm->fifo_size;
+ options[APP_OPTIONS_TX_FIFO_SIZE] = hcm->fifo_size;
+ options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = hcm->private_segment_count;
+ options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = prealloc_fifos;
+ options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
+ options[APP_OPTIONS_TLS_ENGINE] = hcm->tls_engine;
+ options[APP_OPTIONS_PCT_FIRST_ALLOC] = 100;
+ if (appns_id)
+ {
+ options[APP_OPTIONS_FLAGS] |= appns_flags;
+ options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
+ }
+ a->options = options;
+ a->namespace_id = appns_id;
+
+ if ((rv = vnet_application_attach (a)))
+ return clib_error_return (0, "attach returned %d", rv);
+
+ hcm->app_index = a->app_index;
+
+ clib_memset (a_cert, 0, sizeof (*a_cert));
+ a_cert->app_index = a->app_index;
+ vec_validate (a_cert->cert, test_srv_crt_rsa_len);
+ clib_memcpy_fast (a_cert->cert, test_srv_crt_rsa, test_srv_crt_rsa_len);
+ vnet_app_add_tls_cert (a_cert);
+
+ clib_memset (a_key, 0, sizeof (*a_key));
+ a_key->app_index = a->app_index;
+ vec_validate (a_key->key, test_srv_key_rsa_len);
+ clib_memcpy_fast (a_key->key, test_srv_key_rsa, test_srv_key_rsa_len);
+ vnet_app_add_tls_key (a_key);
+ return 0;
+}
+
+static int
+hicn_client_detach ()
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vnet_app_detach_args_t _da, *da = &_da;
+ int rv;
+
+ da->app_index = hcm->app_index;
+ da->api_client_index = ~0;
+ rv = vnet_application_detach (da);
+ hcm->test_client_attached = 0;
+ hcm->app_index = ~0;
+ return rv;
+}
+
+static void *
+hicn_client_thread_fn (void *arg)
+{
+ return 0;
+}
+
+/** Start a transmit thread */
+int
+hicn_client_start_tx_pthread (hicn_client_main_t * hcm)
+{
+ if (hcm->client_thread_handle == 0)
+ {
+ int rv = pthread_create (&hcm->client_thread_handle,
+ NULL /*attr */ ,
+ hicn_client_thread_fn, 0);
+ if (rv)
+ {
+ hcm->client_thread_handle = 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+clib_error_t *
+hicn_client_connect (vlib_main_t * vm, u32 n_clients)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vnet_connect_args_t _a, *a = &_a;
+ int i, rv;
+
+ clib_memset (a, 0, sizeof (*a));
+
+ for (i = 0; i < n_clients; i++)
+ {
+ a->uri = (char *) hcm->connect_uri;
+ a->api_context = i;
+ a->app_index = hcm->app_index;
+
+ vlib_worker_thread_barrier_sync (vm);
+ if ((rv = vnet_connect_uri (a)))
+ {
+ vlib_worker_thread_barrier_release (vm);
+ return clib_error_return (0, "connect returned: %d", rv);
+ }
+ vlib_worker_thread_barrier_release (vm);
+
+ /* Crude pacing for call setups */
+ if ((i % 16) == 0)
+ vlib_process_suspend (vm, 100e-6);
+ ASSERT (i + 1 >= hcm->ready_connections);
+ while (i + 1 - hcm->ready_connections > 128)
+ vlib_process_suspend (vm, 1e-3);
+ }
+
+ return 0;
+}
+
+static clib_error_t *
+hicn_client_command_fn (vlib_main_t * vm,
+ unformat_input_t * input, vlib_cli_command_t * cmd)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ vlib_thread_main_t *thread_main = vlib_get_thread_main ();
+ u64 total_bytes, appns_flags = 0, appns_secret = 0;
+ f64 test_timeout = 20.0, syn_timeout = 20.0, delta;
+ char *default_uri = "hicn://b001::1";
+ uword *event_data = 0, event_type;
+ f64 time_before_connects;
+ u32 n_clients = 1;
+ int preallocate_sessions = 0;
+ char *transfer_type;
+ clib_error_t *error = 0;
+ u8 *appns_id = 0;
+ int i;
+ session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
+ int rv;
+
+ hcm->bytes_to_send = 8192;
+ hcm->no_return = 0;
+ hcm->fifo_size = 128 << 20;
+ hcm->connections_per_batch = 1000;
+ hcm->private_segment_count = 0;
+ hcm->private_segment_size = 0;
+ hcm->no_output = 0;
+ hcm->test_bytes = 0;
+ hcm->test_failed = 0;
+ hcm->vlib_main = vm;
+ hcm->tls_engine = CRYPTO_ENGINE_OPENSSL;
+ hcm->no_copy = 0;
+ hcm->run_test = HICN_CLIENT_STARTING;
+
+ if (thread_main->n_vlib_mains > 1)
+ clib_spinlock_init (&hcm->sessions_lock);
+ vec_free (hcm->connect_uri);
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "uri %s", &hcm->connect_uri))
+ ;
+ else
+ return clib_error_return (0, "failed: unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ /* Store cli process node index for signalling */
+ hcm->cli_node_index =
+ vlib_get_current_process (vm)->node_runtime.node_index;
+
+ if (hcm->is_init == 0)
+ {
+ if (hicn_client_init (vm))
+ return clib_error_return (0, "failed init");
+ }
+
+
+ hcm->ready_connections = 0;
+ hcm->expected_connections = n_clients;
+ hcm->rx_total = 0;
+ hcm->tx_total = 0;
+
+ if (!hcm->connect_uri)
+ {
+ clib_warning ("No uri provided. Using default: %s", default_uri);
+ hcm->connect_uri = format (0, "%s%c", default_uri, 0);
+ }
+
+ vlib_worker_thread_barrier_sync (vm);
+ vnet_session_enable_disable (vm, 1 /* turn on session and transports */ );
+ hicn_hs_enable_disable(vm, 1 /* enable hicn transport */);
+ vlib_worker_thread_barrier_release (vm);
+
+ if ((rv = parse_uri ((char *) hcm->connect_uri, &sep)))
+ return clib_error_return (0, "Uri parse error: %d", rv);
+ hcm->transport_proto = sep.transport_proto;
+ hcm->is_dgram = (sep.transport_proto == TRANSPORT_PROTO_UDP);
+
+#if HICN_CLIENT_PTHREAD
+ hicn_client_start_tx_pthread ();
+#endif
+
+ if (hcm->test_client_attached == 0)
+ {
+ if ((error = hicn_client_attach (appns_id, appns_flags, appns_secret)))
+ {
+ vec_free (appns_id);
+ clib_error_report (error);
+ return error;
+ }
+ vec_free (appns_id);
+ }
+ hcm->test_client_attached = 1;
+
+ /* Turn on the builtin client input nodes */
+ for (i = 0; i < thread_main->n_vlib_mains; i++)
+ vlib_node_set_state (vlib_mains[i], hicn_client_node.index,
+ VLIB_NODE_STATE_POLLING);
+
+ if (preallocate_sessions)
+ pool_init_fixed (hcm->sessions, 1.1 * n_clients);
+
+ /* Fire off connect requests */
+ time_before_connects = vlib_time_now (vm);
+ if ((error = hicn_client_connect (vm, n_clients)))
+ {
+ goto cleanup;
+ }
+
+ /* Park until the sessions come up, or ten seconds elapse... */
+ vlib_process_wait_for_event_or_clock (vm, syn_timeout);
+ event_type = vlib_process_get_events (vm, &event_data);
+ switch (event_type)
+ {
+ case ~0:
+ ec_cli_output ("Timeout with only %d sessions active...",
+ hcm->ready_connections);
+ error = clib_error_return (0, "failed: syn timeout with %d sessions",
+ hcm->ready_connections);
+ goto cleanup;
+
+ case 1:
+ delta = vlib_time_now (vm) - time_before_connects;
+ if (delta != 0.0)
+ ec_cli_output ("%d three-way handshakes in %.2f seconds %.2f/s",
+ n_clients, delta, ((f64) n_clients) / delta);
+
+ hcm->test_start_time = vlib_time_now (hcm->vlib_main);
+ break;
+
+ default:
+ ec_cli_output ("unexpected event(1): %d", event_type);
+ error = clib_error_return (0, "failed: unexpected event(1): %d",
+ event_type);
+ goto cleanup;
+ }
+
+ /* Now wait for the sessions to finish... */
+ vlib_process_wait_for_event_or_clock (vm, test_timeout);
+ event_type = vlib_process_get_events (vm, &event_data);
+ switch (event_type)
+ {
+ case ~0:
+ ec_cli_output ("Timeout with %d sessions still active...",
+ hcm->ready_connections);
+ error = clib_error_return (0, "failed: timeout with %d sessions",
+ hcm->ready_connections);
+ goto cleanup;
+
+ case 2:
+ hcm->test_end_time = vlib_time_now (vm);
+ ec_cli_output ("Test finished at %.6f", hcm->test_end_time);
+ break;
+
+ default:
+ ec_cli_output ("unexpected event(2): %d", event_type);
+ error = clib_error_return (0, "failed: unexpected event(2): %d",
+ event_type);
+ goto cleanup;
+ }
+
+ delta = hcm->test_end_time - hcm->test_start_time;
+ if (delta != 0.0)
+ {
+ total_bytes = (hcm->no_return ? hcm->tx_total : hcm->rx_total);
+ transfer_type = hcm->no_return ? "half-duplex" : "full-duplex";
+ ec_cli_output ("%lld bytes (%lld mbytes, %lld gbytes) in %.2f seconds",
+ total_bytes, total_bytes / (1ULL << 20),
+ total_bytes / (1ULL << 30), delta);
+ ec_cli_output ("%.2f bytes/second %s", ((f64) total_bytes) / (delta),
+ transfer_type);
+ ec_cli_output ("%.4f gbit/second %s",
+ (((f64) total_bytes * 8.0) / delta / 1e9),
+ transfer_type);
+ }
+ else
+ {
+ ec_cli_output ("zero delta-t?");
+ error = clib_error_return (0, "failed: zero delta-t");
+ goto cleanup;
+ }
+
+ if (hcm->test_bytes && hcm->test_failed)
+ error = clib_error_return (0, "failed: test bytes");
+
+cleanup:
+ hcm->run_test = HICN_CLIENT_EXITING;
+ vlib_process_wait_for_event_or_clock (vm, 10e-3);
+ for (i = 0; i < vec_len (hcm->connection_index_by_thread); i++)
+ {
+ vec_reset_length (hcm->connection_index_by_thread[i]);
+ vec_reset_length (hcm->connections_this_batch_by_thread[i]);
+ }
+
+ pool_free (hcm->sessions);
+
+ /* Detach the application, so we can use different fifo sizes next time */
+ if (hcm->test_client_attached)
+ {
+ if (hicn_client_detach ())
+ {
+ error = clib_error_return (0, "failed: app detach");
+ ec_cli_output ("WARNING: app detach failed...");
+ }
+ }
+ if (error)
+ ec_cli_output ("test failed");
+ vec_free (hcm->connect_uri);
+ return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (hicn_client_command, static) =
+{
+ .path = "test hicn hs client",
+ .short_help = "test hicn hs client [uri <hicn://ip6_address/port>]",
+ .function = hicn_client_command_fn,
+ .is_mp_safe = 1,
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+hicn_client_main_init (vlib_main_t * vm)
+{
+ hicn_client_main_t *hcm = &hicn_client_main;
+ hcm->is_init = 0;
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (hicn_client_main_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/host_stack/test/hicn_hs_client.h b/hicn-plugin/src/host_stack/test/hicn_hs_client.h
new file mode 100644
index 000000000..6600608e3
--- /dev/null
+++ b/hicn-plugin/src/host_stack/test/hicn_hs_client.h
@@ -0,0 +1,127 @@
+
+/*
+ * echo_client.h - built-in application layer echo client
+ *
+ * Copyright (c) 2017-2019 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 __included_hicn_hs_client_h__
+#define __included_hicn_hs_client_h__
+
+#include <vnet/vnet.h>
+#include <vnet/ip/ip.h>
+#include <vnet/ethernet/ethernet.h>
+
+#include <vppinfra/hash.h>
+#include <vppinfra/error.h>
+#include <vnet/session/session.h>
+#include <vnet/session/application_interface.h>
+
+typedef struct
+{
+ CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
+ app_session_t data;
+ u64 bytes_to_send;
+ u64 bytes_sent;
+ u64 bytes_to_receive;
+ u64 bytes_received;
+ u64 vpp_session_handle;
+ u8 thread_index;
+} eclient_session_t;
+
+typedef struct
+{
+ /*
+ * Application setup parameters
+ */
+ svm_queue_t *vl_input_queue; /**< vpe input queue */
+ svm_msg_q_t **vpp_event_queue;
+
+ u32 cli_node_index; /**< cli process node index */
+ u32 my_client_index; /**< loopback API client handle */
+ u32 app_index; /**< app index after attach */
+
+ /*
+ * Configuration params
+ */
+ u8 *connect_uri; /**< URI for slave's connect */
+ u64 bytes_to_send; /**< Bytes to send */
+ u32 configured_segment_size;
+ u32 fifo_size;
+ u32 expected_connections; /**< Number of clients/connections */
+ u32 connections_per_batch; /**< Connections to rx/tx at once */
+ u32 private_segment_count; /**< Number of private fifo segs */
+ u32 private_segment_size; /**< size of private fifo segs */
+ u32 tls_engine; /**< TLS engine mbedtls/openssl */
+ u8 is_dgram;
+ u32 no_copy; /**< Don't memcpy data to tx fifo */
+
+ /*
+ * Test state variables
+ */
+ eclient_session_t *sessions; /**< Session pool, shared */
+ clib_spinlock_t sessions_lock;
+ u8 **rx_buf; /**< intermediate rx buffers */
+ u8 *connect_test_data; /**< Pre-computed test data */
+ u32 **connection_index_by_thread;
+ u32 **connections_this_batch_by_thread; /**< active connection batch */
+ pthread_t client_thread_handle;
+
+ volatile u32 ready_connections;
+ volatile u32 finished_connections;
+ volatile u64 rx_total;
+ volatile u64 tx_total;
+ volatile int run_test; /**< Signal start of test */
+
+ f64 test_start_time;
+ f64 test_end_time;
+ u32 prev_conns;
+ u32 repeats;
+ /*
+ * Flags
+ */
+ u8 is_init;
+ u8 test_client_attached;
+ u8 no_return;
+ u8 test_return_packets;
+ int i_am_master;
+ int drop_packets; /**< drop all packets */
+ u8 prealloc_fifos; /**< Request fifo preallocation */
+ u8 no_output;
+ u8 test_bytes;
+ u8 test_failed;
+ u8 transport_proto;
+
+ vlib_main_t *vlib_main;
+} hicn_client_main_t;
+
+enum
+{
+ HICN_CLIENT_STARTING,
+ HICN_CLIENT_RUNNING,
+ HICN_CLIENT_EXITING
+} hicn_client_state_e;
+
+extern hicn_client_main_t hicn_client_main;
+
+vlib_node_registration_t hicn_client_node;
+
+#endif /* __included_hicn_hs_client_h__ */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/hicn-plugin/src/host_stack/test/hicn_hs_server.c b/hicn-plugin/src/host_stack/test/hicn_hs_server.c
new file mode 100644
index 000000000..cab73adb0
--- /dev/null
+++ b/hicn-plugin/src/host_stack/test/hicn_hs_server.c
@@ -0,0 +1,505 @@
+/*
+* 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 <vnet/vnet.h>
+#include <vlibmemory/api.h>
+#include <vnet/session/application.h>
+#include <vnet/session/application_interface.h>
+#include <vnet/session/session.h>
+
+#include "../host_stack.h"
+#include "../route.h"
+
+#define HICN_SERVER_DGB (0)
+#define DBG(_fmt, _args...) \
+ if (HICN_SERVER_DGB) \
+ clib_warning (_fmt, ##_args)
+
+typedef struct
+{
+ /*
+ * Server app parameters
+ */
+ svm_msg_q_t **vpp_queue;
+ svm_queue_t *vl_input_queue; /**< Sever's event queue */
+
+ u32 app_index; /**< Server app index */
+ u32 my_client_index; /**< API client handle */
+ u32 node_index; /**< process node index for event scheduling */
+
+ /*
+ * Config params
+ */
+ u32 fifo_size; /**< Fifo size */
+ u32 rcv_buffer_size; /**< Rcv buffer size */
+ u32 prealloc_fifos; /**< Preallocate fifos */
+ u32 private_segment_count; /**< Number of private segments */
+ u32 private_segment_size; /**< Size of private segments */
+ char *server_uri; /**< Server URI */
+ u32 tls_engine; /**< TLS engine: mbedtls/openssl */
+ u8 is_dgram; /**< set if transport is dgram */
+ /*
+ * Test state
+ */
+ u8 **rx_buf; /**< Per-thread RX buffer */
+ u64 byte_index;
+ u32 **rx_retries;
+ u8 transport_proto;
+ u64 listener_handle; /**< Session handle of the root listener */
+
+ vlib_main_t *vlib_main;
+} hicn_server_main_t;
+
+hicn_server_main_t hicn_server_main;
+
+extern f64 t0;
+
+#define DEFAULT_PRODUCE_SIZE 64 << 20
+static u8 bytes[DEFAULT_PRODUCE_SIZE];
+
+int
+hicn_server_session_accept_callback (session_t * s)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ esm->vpp_queue[s->thread_index] =
+ session_main_get_vpp_event_queue (s->thread_index);
+ s->session_state = SESSION_STATE_READY;
+ esm->byte_index = 0;
+ ASSERT (vec_len (esm->rx_retries) > s->thread_index);
+ vec_validate (esm->rx_retries[s->thread_index], s->session_index);
+ esm->rx_retries[s->thread_index][s->session_index] = 0;
+ return 0;
+}
+
+void
+hicn_server_session_disconnect_callback (session_t * s)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+
+ a->handle = session_handle (s);
+ a->app_index = esm->app_index;
+ vnet_disconnect_session (a);
+}
+
+void
+hicn_server_session_reset_callback (session_t * s)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ vnet_disconnect_args_t _a = { 0 }, *a = &_a;
+ clib_warning ("Reset session %U", format_session, s, 2);
+ a->handle = session_handle (s);
+ a->app_index = esm->app_index;
+ vnet_disconnect_session (a);
+}
+
+int
+hicn_server_session_connected_callback (u32 app_wrk_index, u32 opaque,
+ session_t * s, session_error_t code)
+{
+ clib_warning ("called...");
+ return -1;
+}
+
+int
+hicn_server_add_segment_callback (u32 client_index, u64 segment_handle)
+{
+ /* New heaps may be added */
+ return 0;
+}
+
+int
+hicn_server_redirect_connect_callback (u32 client_index, void *mp)
+{
+ clib_warning ("called...");
+ return -1;
+}
+
+void
+test_bytes (hicn_server_main_t * esm, int actual_transfer)
+{
+ int i;
+ u32 my_thread_id = vlib_get_thread_index ();
+
+ for (i = 0; i < actual_transfer; i++)
+ {
+ if (esm->rx_buf[my_thread_id][i] != ((esm->byte_index + i) & 0xff))
+ {
+ clib_warning ("at %lld expected %d got %d", esm->byte_index + i,
+ (esm->byte_index + i) & 0xff,
+ esm->rx_buf[my_thread_id][i]);
+ }
+ }
+ esm->byte_index += actual_transfer;
+}
+
+/*
+ * If no-echo, just drop the data and be done with it.
+ */
+int
+hicn_server_builtin_server_rx_callback_no_echo (session_t * s)
+{
+ svm_fifo_t *rx_fifo = s->rx_fifo;
+ svm_fifo_dequeue_drop (rx_fifo, svm_fifo_max_dequeue_cons (rx_fifo));
+ return 0;
+}
+
+int hicn_server_enqueue (session_t * s, svm_fifo_t *tx_fifo, u32 thread_index)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ CLIB_UNUSED(u32 n_written);
+ transport_connection_t *transport = session_get_transport(s);
+ hicn_hs_ctx_t *ctx = (hicn_hs_ctx_t *) (transport);
+ hicn_hs_set_next_prod_size (ctx, DEFAULT_PRODUCE_SIZE);
+
+ n_written = app_send_stream_raw (tx_fifo,
+ esm->vpp_queue[thread_index],
+ bytes,
+ DEFAULT_PRODUCE_SIZE,
+ SESSION_IO_EVT_TX,
+ 1 /* do_evt */ , 0);
+
+ return 0;
+}
+
+int
+hicn_server_rx_callback (session_t * s)
+{
+ u32 max_dequeue, max_enqueue;
+ svm_fifo_t *tx_fifo, *rx_fifo;
+ hicn_server_main_t *esm = &hicn_server_main;
+ u32 thread_index = vlib_get_thread_index ();
+
+ ASSERT (s->thread_index == thread_index);
+
+ rx_fifo = s->rx_fifo;
+ tx_fifo = s->tx_fifo;
+
+ ASSERT (rx_fifo->master_thread_index == thread_index);
+ ASSERT (tx_fifo->master_thread_index == thread_index);
+
+ max_enqueue = svm_fifo_max_enqueue_prod (tx_fifo);
+ if (!esm->is_dgram)
+ {
+ max_dequeue = svm_fifo_max_dequeue_cons (rx_fifo);
+ }
+ else
+ {
+ session_dgram_pre_hdr_t ph;
+ svm_fifo_peek (rx_fifo, 0, sizeof (ph), (u8 *) & ph);
+ max_dequeue = ph.data_length - ph.data_offset;
+ if (!esm->vpp_queue[s->thread_index])
+ {
+ svm_msg_q_t *mq;
+ mq = session_main_get_vpp_event_queue (s->thread_index);
+ esm->vpp_queue[s->thread_index] = mq;
+ }
+ max_enqueue -= sizeof (session_dgram_hdr_t);
+ }
+
+ if (max_dequeue == 0)
+ {
+ return hicn_server_enqueue (s, tx_fifo, thread_index);
+ }
+
+ return 0;
+}
+
+static session_cb_vft_t hicn_server_session_cb_vft = {
+ .session_accept_callback = hicn_server_session_accept_callback,
+ .session_disconnect_callback = hicn_server_session_disconnect_callback,
+ .session_connected_callback = hicn_server_session_connected_callback,
+ .add_segment_callback = hicn_server_add_segment_callback,
+ .builtin_app_rx_callback = hicn_server_rx_callback,
+ .session_reset_callback = hicn_server_session_reset_callback
+};
+
+/* Abuse VPP's input queue */
+static int
+create_api_loopback (vlib_main_t * vm)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ api_main_t *am = vlibapi_get_main ();
+ vl_shmem_hdr_t *shmem_hdr;
+
+ shmem_hdr = am->shmem_hdr;
+ esm->vl_input_queue = shmem_hdr->vl_input_queue;
+ esm->my_client_index = vl_api_memclnt_create_internal ("hicn_server",
+ esm->vl_input_queue);
+ return 0;
+}
+
+static int
+hicn_server_attach (u8 * appns_id, u64 appns_flags, u64 appns_secret)
+{
+ vnet_app_add_tls_cert_args_t _a_cert, *a_cert = &_a_cert;
+ vnet_app_add_tls_key_args_t _a_key, *a_key = &_a_key;
+ hicn_server_main_t *esm = &hicn_server_main;
+ vnet_app_attach_args_t _a, *a = &_a;
+ u64 options[APP_OPTIONS_N_OPTIONS];
+ u32 segment_size = 512 << 20;
+
+ clib_memset (a, 0, sizeof (*a));
+ clib_memset (options, 0, sizeof (options));
+
+ hicn_server_session_cb_vft.builtin_app_rx_callback =
+ hicn_server_rx_callback;
+
+ if (esm->private_segment_size)
+ segment_size = esm->private_segment_size;
+
+ a->api_client_index = esm->my_client_index;
+ a->session_cb_vft = &hicn_server_session_cb_vft;
+ a->options = options;
+ a->options[APP_OPTIONS_SEGMENT_SIZE] = segment_size;
+ a->options[APP_OPTIONS_ADD_SEGMENT_SIZE] = segment_size;
+ a->options[APP_OPTIONS_RX_FIFO_SIZE] = esm->fifo_size;
+ a->options[APP_OPTIONS_TX_FIFO_SIZE] = esm->fifo_size;
+ a->options[APP_OPTIONS_PRIVATE_SEGMENT_COUNT] = esm->private_segment_count;
+ a->options[APP_OPTIONS_TLS_ENGINE] = esm->tls_engine;
+ a->options[APP_OPTIONS_PCT_FIRST_ALLOC] = 100;
+ a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] =
+ esm->prealloc_fifos ? esm->prealloc_fifos : 1;
+
+ a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
+ if (appns_id)
+ {
+ a->namespace_id = appns_id;
+ a->options[APP_OPTIONS_FLAGS] |= appns_flags;
+ a->options[APP_OPTIONS_NAMESPACE_SECRET] = appns_secret;
+ }
+
+ if (vnet_application_attach (a))
+ {
+ clib_warning ("failed to attach server");
+ return -1;
+ }
+ esm->app_index = a->app_index;
+
+ clib_memset (a_cert, 0, sizeof (*a_cert));
+ a_cert->app_index = a->app_index;
+ vec_validate (a_cert->cert, test_srv_crt_rsa_len);
+ clib_memcpy_fast (a_cert->cert, test_srv_crt_rsa, test_srv_crt_rsa_len);
+ vnet_app_add_tls_cert (a_cert);
+
+ clib_memset (a_key, 0, sizeof (*a_key));
+ a_key->app_index = a->app_index;
+ vec_validate (a_key->key, test_srv_key_rsa_len);
+ clib_memcpy_fast (a_key->key, test_srv_key_rsa, test_srv_key_rsa_len);
+ vnet_app_add_tls_key (a_key);
+ return 0;
+}
+
+static int
+hicn_server_detach (void)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ vnet_app_detach_args_t _da, *da = &_da;
+ int rv;
+
+ da->app_index = esm->app_index;
+ rv = vnet_application_detach (da);
+ esm->app_index = ~0;
+ return rv;
+}
+
+static int
+hicn_server_listen ()
+{
+ int rv;
+ hicn_server_main_t *esm = &hicn_server_main;
+ vnet_listen_args_t _a, *a = &_a;
+ clib_memset (a, 0, sizeof (*a));
+ a->app_index = esm->app_index;
+ a->uri = esm->server_uri;
+ rv = vnet_bind_uri (a);
+ esm->listener_handle = a->handle;
+ return rv;
+}
+
+static int
+hicn_server_create (vlib_main_t * vm, u8 * appns_id, u64 appns_flags,
+ u64 appns_secret)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ vlib_thread_main_t *vtm = vlib_get_thread_main ();
+ u32 num_threads;
+ int i;
+
+ if (esm->my_client_index == (u32) ~ 0)
+ {
+ if (create_api_loopback (vm))
+ {
+ clib_warning ("failed to create api loopback");
+ return -1;
+ }
+ }
+
+ num_threads = 1 /* main thread */ + vtm->n_threads;
+ vec_validate (hicn_server_main.vpp_queue, num_threads - 1);
+ vec_validate (esm->rx_buf, num_threads - 1);
+ vec_validate (esm->rx_retries, num_threads - 1);
+ for (i = 0; i < vec_len (esm->rx_retries); i++)
+ vec_validate (esm->rx_retries[i],
+ pool_elts (session_main.wrk[i].sessions));
+ esm->rcv_buffer_size = clib_max (esm->rcv_buffer_size, esm->fifo_size);
+ for (i = 0; i < num_threads; i++)
+ vec_validate (esm->rx_buf[i], esm->rcv_buffer_size);
+
+ if (hicn_server_attach (appns_id, appns_flags, appns_secret))
+ {
+ clib_warning ("failed to attach server");
+ return -1;
+ }
+ if (hicn_server_listen ())
+ {
+ clib_warning ("failed to start listening");
+ if (hicn_server_detach ())
+ clib_warning ("failed to detach");
+ return -1;
+ }
+ return 0;
+}
+
+static clib_error_t *
+hicn_server_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ u8 server_uri_set = 0, *appns_id = 0;
+ u64 tmp, appns_flags = 0, appns_secret = 0;
+ char *default_uri = "hicn://b001::1/64";
+ int rv, is_stop = 0;
+ session_endpoint_cfg_t sep = SESSION_ENDPOINT_CFG_NULL;
+
+ esm->fifo_size = 128 << 20;
+ esm->rcv_buffer_size = 2 << 20;
+ esm->prealloc_fifos = 0;
+ esm->private_segment_count = 0;
+ esm->private_segment_size = 0;
+ esm->tls_engine = CRYPTO_ENGINE_OPENSSL;
+ vec_free (esm->server_uri);
+
+ while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (input, "uri %s", &esm->server_uri))
+ server_uri_set = 1;
+ else if (unformat (input, "fifo-size %d", &esm->fifo_size))
+ esm->fifo_size <<= 10;
+ else if (unformat (input, "rcv-buf-size %d", &esm->rcv_buffer_size))
+ ;
+ else if (unformat (input, "prealloc-fifos %d", &esm->prealloc_fifos))
+ ;
+ else if (unformat (input, "private-segment-count %d",
+ &esm->private_segment_count))
+ ;
+ else if (unformat (input, "private-segment-size %U",
+ unformat_memory_size, &tmp))
+ {
+ if (tmp >= 0x100000000ULL)
+ return clib_error_return
+ (0, "private segment size %lld (%llu) too large", tmp, tmp);
+ esm->private_segment_size = tmp;
+ }
+ else if (unformat (input, "appns %_%v%_", &appns_id))
+ ;
+ else if (unformat (input, "all-scope"))
+ appns_flags |= (APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE
+ | APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE);
+ else if (unformat (input, "local-scope"))
+ appns_flags |= APP_OPTIONS_FLAGS_USE_LOCAL_SCOPE;
+ else if (unformat (input, "global-scope"))
+ appns_flags |= APP_OPTIONS_FLAGS_USE_GLOBAL_SCOPE;
+ else if (unformat (input, "secret %lu", &appns_secret))
+ ;
+ else if (unformat (input, "stop"))
+ is_stop = 1;
+ else if (unformat (input, "tls-engine %d", &esm->tls_engine))
+ ;
+ else
+ return clib_error_return (0, "failed: unknown input `%U'",
+ format_unformat_error, input);
+ }
+
+ if (is_stop)
+ {
+ if (esm->app_index == (u32) ~ 0)
+ {
+ clib_warning ("server not running");
+ return clib_error_return (0, "failed: server not running");
+ }
+ rv = hicn_server_detach ();
+ if (rv)
+ {
+ clib_warning ("failed: detach");
+ return clib_error_return (0, "failed: server detach %d", rv);
+ }
+ return 0;
+ }
+
+ vnet_session_enable_disable (vm, 1 /* turn on TCP, etc. */ );
+ hicn_hs_enable_disable(vm, 1 /* enable hicn transport */);
+
+ if (!server_uri_set)
+ {
+ clib_warning ("No uri provided! Using default: %s", default_uri);
+ esm->server_uri = (char *) format (0, "%s%c", default_uri, 0);
+ }
+
+ if ((rv = parse_uri ((char *) esm->server_uri, &sep)))
+ return clib_error_return (0, "Uri parse error: %d", rv);
+ esm->transport_proto = sep.transport_proto;
+ esm->is_dgram = 0;
+
+ rv = hicn_server_create (vm, appns_id, appns_flags, appns_secret);
+ vec_free (appns_id);
+ if (rv)
+ {
+ vec_free (esm->server_uri);
+ return clib_error_return (0, "failed: server_create returned %d", rv);
+ }
+
+ return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (hicn_server_create_command, static) =
+{
+ .path = "test hicn hs server",
+ .short_help = "test echo server proto <proto> [no echo][fifo-size <mbytes>]"
+ "[rcv-buf-size <bytes>][prealloc-fifos <count>]"
+ "[private-segment-count <count>][private-segment-size <bytes[m|g]>]"
+ "[uri <hicn://ip/plen>]",
+ .function = hicn_server_create_command_fn,
+};
+/* *INDENT-ON* */
+
+clib_error_t *
+hicn_server_main_init (vlib_main_t * vm)
+{
+ hicn_server_main_t *esm = &hicn_server_main;
+ esm->my_client_index = ~0;
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (hicn_server_main_init);
+
+/*
+* fd.io coding-style-patch-verification: ON
+*
+* Local Variables:
+* eval: (c-set-style "gnu")
+* End:
+*/
diff --git a/hicn-plugin/src/host_stack/testbed/Dockerfile b/hicn-plugin/src/host_stack/testbed/Dockerfile
new file mode 100644
index 000000000..4e7005938
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/Dockerfile
@@ -0,0 +1,46 @@
+FROM ubuntu:18.04
+
+ARG USERNAME=ubuntu
+ARG USER_UID=1000
+ARG USER_GID=$USER_UID
+
+ARG VPP_GRP=vpp
+ARG VPP_GID=998
+
+ARG WORKDIR=/home/ubuntu
+
+RUN apt-get update \
+ && apt-get -y install --no-install-recommends apt-utils sudo dialog build-essential \
+ cmake cppcheck valgrind curl autoconf automake ccache debhelper dkms git libtool \
+ libapr1-dev dh-systemd libconfuse-dev git-review exuberant-ctags cscope pkg-config \
+ lcov chrpath autoconf indent clang-format libnuma-dev python-all python3-all \
+ python3-setuptools python-dev python-virtualenv python-pip libffi6 check \
+ libboost-all-dev libffi-dev python3-ply libmbedtls-dev cmake ninja-build uuid-dev \
+ python3-jsonschema gdb libssl-dev python-setuptools zsh 2>&1 \
+ #
+ # Verify git, process tools, lsb-release (useful for CLI installs) installed
+ && apt-get -y install git procps lsb-release curl iproute2 \
+ #
+ # Create a non-root user to use if preferred - see https://aka.ms/vscode-remote/containers/non-root-user.
+ && groupadd --gid $USER_GID $USERNAME \
+ && useradd -s /bin/bash --uid $USER_UID --gid $USER_GID -m $USERNAME \
+ # [Optional] Uncomment the next three lines to add sudo support
+ && apt-get install -y sudo \
+ && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
+ && chmod 0440 /etc/sudoers.d/$USERNAME \
+ # Create vpp group
+ && groupadd --gid $VPP_GID $VPP_GRP \
+ #
+ && mkdir -p $WORKDIR \
+ #
+ # Clean up
+ && apt-get autoremove -y \
+ && apt-get clean -y \
+ && rm -rf /var/lib/apt/lists/*
+
+USER $USERNAME
+COPY init.sh /init.sh
+
+WORKDIR $WORKDIR
+
+CMD ["bash", "/init.sh"]
diff --git a/hicn-plugin/src/host_stack/testbed/client-startup.txt b/hicn-plugin/src/host_stack/testbed/client-startup.txt
new file mode 100644
index 000000000..7165265b3
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/client-startup.txt
@@ -0,0 +1,6 @@
+create interface memif id 0 master
+set int state memif0/0 up
+set int ip addr memif0/0 192.168.10.1/24
+set int ip addr memif0/0 2001::1/64
+ip route add b001::/64 via 2001::2 memif0/0
+#hicn enable b001::/64 \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/testbed/init.sh b/hicn-plugin/src/host_stack/testbed/init.sh
new file mode 100644
index 000000000..3017c2fea
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/init.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+sudo modprobe uio_pci_generic
+sudo cp /home/ubuntu/host-stack/install/lib/libhicn.so /usr/lib/libhicn.so
+
+tail -f /dev/null \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/testbed/run-client-server.sh b/hicn-plugin/src/host_stack/testbed/run-client-server.sh
new file mode 100644
index 000000000..53388cdda
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/run-client-server.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+docker run -d \
+ --privileged \
+ --cap-add=ALL \
+ --security-opt seccomp=unconfined \
+ --hostname=vpp-client \
+ -e STARTUP_CONF=/home/ubuntu/host-stack/vpp/testbed/startup-client.conf \
+ -v /home/ubuntu/host-stack:/home/ubuntu/host-stack \
+ -v /dev:/dev -v /lib/modules:/lib/modules \
+ -v /var/run/vpp:/var/run/vpp \
+ --name vpp-client vpp-develop
+
+docker run -d \
+ --privileged \
+ --cap-add=SYS_PTRACE \
+ --security-opt seccomp=unconfined \
+ --hostname=vpp-server \
+ -e STARTUP_CONF=/home/ubuntu/host-stack/vpp/testbed/startup-server.conf \
+ --cap-add=NET_ADMIN \
+ -v /home/ubuntu/host-stack:/home/ubuntu/host-stack \
+ -v /dev:/dev -v /lib/modules:/lib/modules \
+ -v /var/run/vpp:/var/run/vpp \
+ --name vpp-server vpp-develop \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/testbed/server-startup.txt b/hicn-plugin/src/host_stack/testbed/server-startup.txt
new file mode 100644
index 000000000..1b4d54338
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/server-startup.txt
@@ -0,0 +1,7 @@
+create interface memif id 0 slave
+set int state memif0/0 up
+set int ip addr memif0/0 192.168.10.2/24
+set int ip addr memif0/0 2001::2/64
+hicn hs set local prefix b001::/16
+#test hicn hs server uri hicn://b001::/64
+#hicn enable b001::/64
diff --git a/hicn-plugin/src/host_stack/testbed/startup-client.conf b/hicn-plugin/src/host_stack/testbed/startup-client.conf
new file mode 100644
index 000000000..fb0c89c87
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/startup-client.conf
@@ -0,0 +1,188 @@
+
+unix {
+ nodaemon
+ interactive
+ log /var/log/vpp/vpp.log
+ full-coredump
+ cli-listen /run/vpp/cli.sock
+ gid vpp
+ startup-config /home/ubuntu/host-stack/vpp/testbed/client-startup.txt
+}
+
+api-trace {
+## This stanza controls binary API tracing. Unless there is a very strong reason,
+## please leave this feature enabled.
+ on
+## Additional parameters:
+##
+## To set the number of binary API trace records in the circular buffer, configure nitems
+##
+## nitems <nnn>
+##
+## To save the api message table decode tables, configure a filename. Results in /tmp/<filename>
+## Very handy for understanding api message changes between versions, identifying missing
+## plugins, and so forth.
+##
+## save-api-table <filename>
+}
+
+api-segment {
+ gid vpp
+}
+
+socksvr {
+ default
+}
+
+cpu {
+ ## In the VPP there is one main thread and optionally the user can create worker(s)
+ ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
+
+ ## Manual pinning of thread(s) to CPU core(s)
+
+ ## Set logical CPU core where main thread runs, if main core is not set
+ ## VPP will use core 1 if available
+ main-core 1
+
+ ## Set logical CPU core(s) where worker threads are running
+ # corelist-workers 2-3,18-19
+
+ ## Automatic pinning of thread(s) to CPU core(s)
+
+ ## Sets number of CPU core(s) to be skipped (1 ... N-1)
+ ## Skipped CPU core(s) are not used for pinning main thread and working thread(s).
+ ## The main thread is automatically pinned to the first available CPU core and worker(s)
+ ## are pinned to next free CPU core(s) after core assigned to main thread
+ # skip-cores 4
+
+ ## Specify a number of workers to be created
+ ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s)
+ ## and main thread's CPU core
+ # workers 2
+
+ ## Set scheduling policy and priority of main and worker threads
+
+ ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH)
+ ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR)
+ # scheduler-policy fifo
+
+ ## Scheduling priority is used only for "real-time policies (fifo and rr),
+ ## and has to be in the range of priorities supported for a particular policy
+ # scheduler-priority 50
+}
+
+buffers {
+ ## Increase number of buffers allocated, needed only in scenarios with
+ ## large number of interfaces and worker threads. Value is per numa node.
+# Default is 16384 (8192 if running unpriviledged)
+ buffers-per-numa 600000
+ ## Size of buffer data area
+ ## Default is 2048
+ # default data-size 2048
+}
+
+# dpdk {
+ ## Change default settings for all interfaces
+ # dev default {
+ ## Number of receive queues, enables RSS
+ ## Default is 1
+ # num-rx-queues 3
+
+ ## Number of transmit queues, Default is equal
+ ## to number of worker threads or 1 if no workers treads
+ # num-tx-queues 3
+
+ ## Number of descriptors in transmit and receive rings
+ ## increasing or reducing number can impact performance
+ ## Default is 1024 for both rx and tx
+ # num-rx-desc 512
+ # num-tx-desc 512
+
+ ## VLAN strip offload mode for interface
+ ## Default is off
+ # vlan-strip-offload on
+
+ ## TCP Segment Offload
+ ## Default is off
+ ## To enable TSO, 'enable-tcp-udp-checksum' must be set
+ # tso on
+
+ ## Devargs
+ ## device specific init args
+ ## Default is NULL
+ # devargs safe-mode-support=1,pipeline-mode-support=1
+ # }
+
+ ## Whitelist specific interface by specifying PCI address
+ # dev 0000:13:00.0
+
+ ## Blacklist specific device type by specifying PCI vendor:device
+ ## Whitelist entries take precedence
+ # blacklist 8086:10fb
+
+ ## Set interface name
+ # dev 0000:02:00.1 {
+ # name eth0
+ # }
+
+ ## Whitelist specific interface by specifying PCI address and in
+ ## addition specify custom parameters for this interface
+ # dev 0000:02:00.1 {
+ # num-rx-queues 2
+ # }
+
+ ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci,
+ ## uio_pci_generic or auto (default)
+ # uio-driver vfio-pci
+
+ ## Disable multi-segment buffers, improves performance but
+ ## disables Jumbo MTU support
+ # no-multi-seg
+
+ ## Change hugepages allocation per-socket, needed only if there is need for
+ ## larger number of mbufs. Default is 256M on each detected CPU socket
+ # socket-mem 2048,2048
+
+ ## Disables UDP / TCP TX checksum offload. Typically needed for use
+ ## faster vector PMDs (together with no-multi-seg)
+ # no-tx-checksum-offload
+
+ ## Enable UDP / TCP TX checksum offload
+ ## This is the reversed option of 'no-tx-checksum-offload'
+ # enable-tcp-udp-checksum
+# }
+
+
+plugins {
+ ## Adjusting the plugin path depending on where the VPP plugins are
+ path /home/ubuntu/host-stack/vpp/build-root/install-vpp_debug-native/vpp/lib/x86_64-linux-gnu/vpp_plugins:/home/ubuntu/host-stack/vpp/build-root/install-vpp_debug-native/vpp/lib/vpp_plugins:/home/ubuntu/host-stack/install/lib/vpp_plugins
+ ## Disable all plugins by default and then selectively enable specific plugins
+ plugin default { enable }
+ plugin dpdk_plugin.so { disable }
+ plugin hicn_plugin.so { enable }
+# plugin hicn_plugin.so { enable }
+
+
+ ## Enable all plugins by default and then selectively disable specific plugins
+ # plugin dpdk_plugin.so { disable }
+ # plugin acl_plugin.so { disable }
+}
+
+## Statistics Segment
+# statseg {
+ # socket-name <filename>, name of the stats segment socket
+ # defaults to /run/vpp/stats.sock
+ # size <nnn>[KMG], size of the stats segment, defaults to 32mb
+ # per-node-counters on | off, defaults to none
+ # update-interval <f64-seconds>, sets the segment scrape / update interval
+# }
+
+#hicn {
+# pit-size 2000000
+# cs-size 1000000
+# cs-reserved-app 10
+#}
+
+session { evt_qs_memfd_seg }
+socksvr { socket-name /tmp/vpp-api.sock}
+tcp {cc-algo cubic}
diff --git a/hicn-plugin/src/host_stack/testbed/startup-server.conf b/hicn-plugin/src/host_stack/testbed/startup-server.conf
new file mode 100644
index 000000000..46fc220d8
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/startup-server.conf
@@ -0,0 +1,189 @@
+
+unix {
+ nodaemon
+ interactive
+ log /var/log/vpp/vpp.log
+ full-coredump
+ cli-listen /run/vpp/cli.sock
+ gid vpp
+ startup-config /home/ubuntu/host-stack/vpp/testbed/server-startup.txt
+}
+
+api-trace {
+## This stanza controls binary API tracing. Unless there is a very strong reason,
+## please leave this feature enabled.
+ on
+## Additional parameters:
+##
+## To set the number of binary API trace records in the circular buffer, configure nitems
+##
+## nitems <nnn>
+##
+## To save the api message table decode tables, configure a filename. Results in /tmp/<filename>
+## Very handy for understanding api message changes between versions, identifying missing
+## plugins, and so forth.
+##
+## save-api-table <filename>
+}
+
+api-segment {
+ gid vpp
+}
+
+socksvr {
+ default
+}
+
+cpu {
+ ## In the VPP there is one main thread and optionally the user can create worker(s)
+ ## The main thread and worker thread(s) can be pinned to CPU core(s) manually or automatically
+
+ ## Manual pinning of thread(s) to CPU core(s)
+
+ ## Set logical CPU core where main thread runs, if main core is not set
+ ## VPP will use core 1 if available
+ main-core 2
+
+ ## Set logical CPU core(s) where worker threads are running
+ # corelist-workers 2-3,18-19
+
+ ## Automatic pinning of thread(s) to CPU core(s)
+
+ ## Sets number of CPU core(s) to be skipped (1 ... N-1)
+ ## Skipped CPU core(s) are not used for pinning main thread and working thread(s).
+ ## The main thread is automatically pinned to the first available CPU core and worker(s)
+ ## are pinned to next free CPU core(s) after core assigned to main thread
+ # skip-cores 4
+
+ ## Specify a number of workers to be created
+ ## Workers are pinned to N consecutive CPU cores while skipping "skip-cores" CPU core(s)
+ ## and main thread's CPU core
+ # workers 2
+
+ ## Set scheduling policy and priority of main and worker threads
+
+ ## Scheduling policy options are: other (SCHED_OTHER), batch (SCHED_BATCH)
+ ## idle (SCHED_IDLE), fifo (SCHED_FIFO), rr (SCHED_RR)
+ # scheduler-policy fifo
+
+ ## Scheduling priority is used only for "real-time policies (fifo and rr),
+ ## and has to be in the range of priorities supported for a particular policy
+ # scheduler-priority 50
+}
+
+buffers {
+ ## Increase number of buffers allocated, needed only in scenarios with
+ ## large number of interfaces and worker threads. Value is per numa node.
+# Default is 16384 (8192 if running unpriviledged)
+ buffers-per-numa 600000
+ ## Size of buffer data area
+ ## Default is 2048
+ # default data-size 2048
+}
+
+# dpdk {
+ ## Change default settings for all interfaces
+ # dev default {
+ ## Number of receive queues, enables RSS
+ ## Default is 1
+ # num-rx-queues 3
+
+ ## Number of transmit queues, Default is equal
+ ## to number of worker threads or 1 if no workers treads
+ # num-tx-queues 3
+
+ ## Number of descriptors in transmit and receive rings
+ ## increasing or reducing number can impact performance
+ ## Default is 1024 for both rx and tx
+ # num-rx-desc 512
+ # num-tx-desc 512
+
+ ## VLAN strip offload mode for interface
+ ## Default is off
+ # vlan-strip-offload on
+
+ ## TCP Segment Offload
+ ## Default is off
+ ## To enable TSO, 'enable-tcp-udp-checksum' must be set
+ # tso on
+
+ ## Devargs
+ ## device specific init args
+ ## Default is NULL
+ # devargs safe-mode-support=1,pipeline-mode-support=1
+ # }
+
+ ## Whitelist specific interface by specifying PCI address
+ # dev 0000:13:00.1
+
+ ## Blacklist specific device type by specifying PCI vendor:device
+ ## Whitelist entries take precedence
+ # blacklist 8086:10fb
+
+ ## Set interface name
+ # dev 0000:02:00.1 {
+ # name eth0
+ # }
+
+ ## Whitelist specific interface by specifying PCI address and in
+ ## addition specify custom parameters for this interface
+ # dev 0000:02:00.1 {
+ # num-rx-queues 2
+ # }
+
+ ## Change UIO driver used by VPP, Options are: igb_uio, vfio-pci,
+ ## uio_pci_generic or auto (default)
+ # uio-driver vfio-pci
+
+ ## Disable multi-segment buffers, improves performance but
+ ## disables Jumbo MTU support
+ # no-multi-seg
+
+ ## Change hugepages allocation per-socket, needed only if there is need for
+ ## larger number of mbufs. Default is 256M on each detected CPU socket
+ # socket-mem 2048,2048
+
+ ## Disables UDP / TCP TX checksum offload. Typically needed for use
+ ## faster vector PMDs (together with no-multi-seg)
+ # no-tx-checksum-offload
+
+ ## Enable UDP / TCP TX checksum offload
+ ## This is the reversed option of 'no-tx-checksum-offload'
+ # enable-tcp-udp-checksum
+# }
+
+
+plugins {
+ ## Adjusting the plugin path depending on where the VPP plugins are
+ path /home/ubuntu/host-stack/vpp/build-root/install-vpp_debug-native/vpp/lib/x86_64-linux-gnu/vpp_plugins:/home/ubuntu/host-stack/vpp/build-root/install-vpp_debug-native/vpp/lib/vpp_plugins:/home/ubuntu/host-stack/install/lib/vpp_plugins
+ ## Disable all plugins by default and then selectively enable specific plugins
+ plugin default { enable }
+ plugin dpdk_plugin.so { disable }
+ plugin hicn_plugin.so { enable }
+# plugin memif_plugin.so { enable }
+# plugin hicn_plugin.so { enable }
+
+
+ ## Enable all plugins by default and then selectively disable specific plugins
+ # plugin dpdk_plugin.so { disable }
+ # plugin acl_plugin.so { disable }
+}
+
+## Statistics Segment
+# statseg {
+ # socket-name <filename>, name of the stats segment socket
+ # defaults to /run/vpp/stats.sock
+ # size <nnn>[KMG], size of the stats segment, defaults to 32mb
+ # per-node-counters on | off, defaults to none
+ # update-interval <f64-seconds>, sets the segment scrape / update interval
+# }
+
+#hicn {
+# pit-size 2000000
+# cs-size 1000000
+# cs-reserved-app 10
+#}
+
+session { evt_qs_memfd_seg }
+socksvr { socket-name /tmp/vpp-api.sock}
+tcp {cc-algo cubic}
diff --git a/hicn-plugin/src/host_stack/testbed/test_hicn_hs.txt b/hicn-plugin/src/host_stack/testbed/test_hicn_hs.txt
new file mode 100644
index 000000000..73a5b15f5
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/test_hicn_hs.txt
@@ -0,0 +1,6 @@
+hicn hs set local prefix b001::/8
+test hicn hs server uri hicn://b001::/64
+test hicn hs client uri hicn://b001::1/64
+
+
+b hicn_hs.c:772 if ctx->snd_nxt == 46604 \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/testbed/vcl.conf b/hicn-plugin/src/host_stack/testbed/vcl.conf
new file mode 100644
index 000000000..694a3e3a1
--- /dev/null
+++ b/hicn-plugin/src/host_stack/testbed/vcl.conf
@@ -0,0 +1,7 @@
+vcl {
+ rx-fifo-size 4000000
+ tx-fifo-size 4000000
+ app-scope-local
+ app-scope-global
+ api-socket-name /tmp/vpp-api.sock
+} \ No newline at end of file
diff --git a/hicn-plugin/src/host_stack/utils.h b/hicn-plugin/src/host_stack/utils.h
new file mode 100644
index 000000000..67568d568
--- /dev/null
+++ b/hicn-plugin/src/host_stack/utils.h
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+
+/* Compute TCP checksum in software when offloading is disabled for a connection */
+
+#ifndef __HICN_HS_UTILS_H__
+#define __HICN_HS_UTILS_H__
+
+#include <vnet/ip/ip4.h>
+#include <vnet/ip/ip6.h>
+#include <vnet/tcp/tcp.h>
+
+always_inline u16
+ip6_tcp_compute_checksum_custom (vlib_main_t * vm, vlib_buffer_t * p0,
+ ip46_address_t * src, ip46_address_t * dst)
+{
+ ip_csum_t sum0;
+ u16 payload_length_host_byte_order;
+ u32 i;
+
+ /* Initialize checksum with ip header. */
+ sum0 = clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, p0)) +
+ clib_host_to_net_u16 (IP_PROTOCOL_TCP);
+ payload_length_host_byte_order = vlib_buffer_length_in_chain (vm, p0);
+
+ for (i = 0; i < ARRAY_LEN (src->ip6.as_uword); i++)
+ {
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&src->ip6.as_uword[i], uword));
+ sum0 = ip_csum_with_carry
+ (sum0, clib_mem_unaligned (&dst->ip6.as_uword[i], uword));
+ }
+
+ return ip_calculate_l4_checksum (vm, p0, sum0,
+ payload_length_host_byte_order, NULL, 0,
+ NULL);
+}
+
+always_inline u16
+ip4_tcp_compute_checksum_custom (vlib_main_t * vm, vlib_buffer_t * p0,
+ ip46_address_t * src, ip46_address_t * dst)
+{
+ ip_csum_t sum0;
+ u32 payload_length_host_byte_order;
+
+ payload_length_host_byte_order = vlib_buffer_length_in_chain (vm, p0);
+ sum0 =
+ clib_host_to_net_u32 (payload_length_host_byte_order +
+ (IP_PROTOCOL_TCP << 16));
+
+ sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&src->ip4, u32));
+ sum0 = ip_csum_with_carry (sum0, clib_mem_unaligned (&dst->ip4, u32));
+
+ return ip_calculate_l4_checksum (vm, p0, sum0,
+ payload_length_host_byte_order, NULL, 0,
+ NULL);
+}
+
+always_inline u16
+hicn_hs_compute_checksum (hicn_hs_ctx_t * ctx, vlib_buffer_t * b)
+{
+ u16 checksum = 0;
+ if (PREDICT_FALSE (ctx->cfg_flags & HICN_HS_CFG_F_NO_CSUM_OFFLOAD))
+ {
+ hicn_hs_worker_t *wrk = hicn_hs_get_worker_by_context (ctx);
+ vlib_main_t *vm = wrk->vm;
+ ip46_address_t local_ip = {0};
+
+ if (ctx->c_is_ip4)
+ checksum = ip4_tcp_compute_checksum_custom
+ (vm, b, &local_ip, &ctx->c_rmt_ip);
+ else
+ checksum = ip6_tcp_compute_checksum_custom
+ (vm, b, &local_ip, &ctx->c_rmt_ip);
+ }
+ else
+ {
+ b->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+ }
+ return checksum;
+}
+
+#endif /* __HICN_HS_UTILS_H__ */