diff options
author | Mauro Sardara <msardara@cisco.com> | 2020-03-24 17:34:14 +0000 |
---|---|---|
committer | Mauro Sardara <msardara@cisco.com> | 2020-09-14 17:31:15 +0000 |
commit | 88509fe353767cbde707c3e3b1f29392957819f3 (patch) | |
tree | cccd51bac7966cd3138c525e8075d90341184a66 /hicn-plugin/src/host_stack | |
parent | d875ae92a7fa1eaab3bc2616aeeedfc64a81fea4 (diff) |
[HICN-574] Host stack plugin for VPP.
Signed-off-by: Mauro Sardara <msardara@cisco.com>
Change-Id: I8d8fdffef31a7013265d6529c5f52f3d5ec70d18
Signed-off-by: Mauro Sardara <msardara@cisco.com>
Signed-off-by: Mauro <you@example.com>
Signed-off-by: Mauro Sardara <msardara@cisco.com>
Diffstat (limited to 'hicn-plugin/src/host_stack')
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__ */ |