diff options
Diffstat (limited to 'hicn-plugin/src/host_stack/inlines.h')
-rw-r--r-- | hicn-plugin/src/host_stack/inlines.h | 520 |
1 files changed, 520 insertions, 0 deletions
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 |