From dfd7ce27fea04c1a76844e21286c2b1d6653e153 Mon Sep 17 00:00:00 2001 From: Jim Gibson Date: Mon, 20 Feb 2017 11:53:54 -0500 Subject: Initial Commit: VPP cicn VPP plugin Change-Id: If1b965f0a4b7cfacda8f6caf6925072a9007ffb4 Signed-off-by: Jim Gibson --- cicn-plugin/cicn/cicn_hello.c | 439 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 439 insertions(+) create mode 100644 cicn-plugin/cicn/cicn_hello.c (limited to 'cicn-plugin/cicn/cicn_hello.c') diff --git a/cicn-plugin/cicn/cicn_hello.c b/cicn-plugin/cicn/cicn_hello.c new file mode 100644 index 00000000..0117a413 --- /dev/null +++ b/cicn-plugin/cicn/cicn_hello.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * cicn_hello.c - ICN hello protocol operation + */ + +#include +#include + +#include +#include +#include + +#include + +#include +#include + +static vlib_node_registration_t icn_hello_process_node; + +/* Stats string values */ +static char *icnhelloprocess_error_strings[] = { +#define _(sym,string) string, + foreach_icnhelloprocess_error +#undef _ +}; + +/* + * When face is created/hello enabled, fill in adjacency information + */ +clib_error_t * +cicn_hello_adj_update (i32 faceid, int enable) +{ + clib_error_t *rv = 0; + + int ret; + cicn_main_t *sm = &cicn_main; + cicn_hello_name_t *hello_name = &sm->hello_name; + cicn_face_db_entry_t *face; + cicn_hello_adj_t *hello_adj; + cicn_hello_fcd_t *fcd; + struct sockaddr_in *addr; + + ret = cicn_face_entry_find_by_id (faceid, &face); + if (ret != AOK) + { + rv = clib_error_return (0, "face id %d not found", faceid); + goto done; + } + if (face->app_face) + { + rv = + clib_error_return (0, + "face id %d is app face, hello protocol disallowed", + faceid); + goto done; + } + + /* Set the cicn_hello_adj struct values */ + + hello_adj = &sm->cicn_hello_adjs[faceid]; + + if (enable) + { + if (hello_adj->active) + { + rv = + clib_error_return (0, "face id %d hello protocol already enabled", + faceid); + goto done; + } + + hello_adj->ha_swif = face->swif; + + clib_memcpy (face->fe_ha_name_cmn, &hello_name->hn_wf[0], + CICN_HELLO_NAME_CMN_FLEN); + + fcd = &face->fe_ha_fcd_loc; + addr = &face->src_addr; + memset (&fcd->fcd_v[0], 0, sizeof (fcd->fcd_v)); + clib_memcpy (&fcd->fcd_v[0], &addr->sin_addr.s_addr, sizeof (u32)); + clib_memcpy (&fcd->fcd_v[sizeof (u32)], &addr->sin_port, sizeof (u16)); + fcd->fcd_v_len = CICN_HELLO_NAME_FACEID_V_LEN; + + // for now, assume nbr's faceid vs. receiving in iMsg notification + fcd = &face->fe_ha_fcd_nbr; + addr = &face->dest_addr; + memset (&fcd->fcd_v[0], 0, sizeof (fcd->fcd_v)); + clib_memcpy (&fcd->fcd_v[0], &addr->sin_addr.s_addr, sizeof (u32)); + clib_memcpy (&fcd->fcd_v[sizeof (u32)], &addr->sin_port, sizeof (u16)); + fcd->fcd_v_len = CICN_HELLO_NAME_FACEID_V_LEN; + + hello_adj->active = 1; + + /* Increment the number of active adjacencies */ + sm->n_active_hello_adjs++; + } + else + { + if (!hello_adj->active) + { + rv = + clib_error_return (0, + "face id %d hello protocol already disabled", + faceid); + goto done; + } + + hello_adj->active = 0; + hello_adj->ha_swif = 0; + + fcd = &face->fe_ha_fcd_loc; + memset (fcd, 0, sizeof (*fcd)); + + fcd = &face->fe_ha_fcd_nbr; + memset (fcd, 0, sizeof (*fcd)); + + /* Decrement the number of active adjacencies */ + sm->n_active_hello_adjs--; + } + + cicn_face_flags_update (face, enable, CICN_FACE_FLAG_HELLO_DOWN); + +done: + return (rv); +} + +/* + * Every hello period, create a hello packet for a peer, to be sent out, + * using buffer for buf_idx + */ +static void +cicn_hello_packet_build (u32 bi0, cicn_hello_adj_t * hello_adj, + cicn_face_db_entry_t * face) +{ + cicn_main_t *sm = &cicn_main; + vlib_main_t *vm = sm->vlib_main; + + vlib_buffer_t *b0 = vlib_get_buffer (vm, bi0); + vnet_buffer (b0)->sw_if_index[VLIB_RX] = hello_adj->ha_swif; //TODO: correct? + vnet_buffer (b0)->sw_if_index[VLIB_TX] = ~0; + + /* Increment the last sent seq num (i.e. first sent is 1, not 0) */ + hello_adj->last_sent_seq_num++; + + u32 icn_name_len = CICN_TLV_HDR_LEN + sm->hello_name.hn_wf_v_len; + + u32 icn_len = sizeof (cicn_packet_hdr_t) + CICN_TLV_HDR_LEN + icn_name_len; + + /* Zero all the way through the icn packet header, not ICN message */ + u8 *ptr0 = vlib_buffer_get_current (b0); + memset (ptr0, 0, sizeof (ip4_header_t) + sizeof (udp_header_t) + + sizeof (cicn_packet_hdr_t)); + + /* Build IP header in place */ + ip4_header_t *ip0 = (ip4_header_t *) ptr0; + b0->current_length = sizeof (ip4_header_t); + ASSERT ((((uintptr_t) ip0) & 0x3) == 0); // assert alignment for assigns below + + ip0->ip_version_and_header_length = 0x45; + ip0->ttl = 128; + ip0->protocol = IP_PROTOCOL_UDP; + ip0->src_address.as_u32 = face->src_addr.sin_addr.s_addr; + ip0->dst_address.as_u32 = face->dest_addr.sin_addr.s_addr; + ip0->length = + clib_host_to_net_u16 (sizeof (ip4_header_t) + sizeof (udp_header_t) + + icn_len); + ip0->checksum = ip4_header_checksum (ip0); + + /* Build UDP header in place */ + udp_header_t *udp0 = (udp_header_t *) (ip0 + 1); + b0->current_length += sizeof (udp_header_t); + + udp0->src_port = face->src_addr.sin_port; + udp0->dst_port = face->dest_addr.sin_port; + udp0->checksum = 0x0000; + udp0->length = clib_host_to_net_u16 (sizeof (udp_header_t) + icn_len); + + /* Build ICN header */ + cicn_packet_hdr_t *h = (cicn_packet_hdr_t *) (udp0 + 1); + b0->current_length += icn_len; + + h->pkt_ver = CICN_PROTO_VERSION_CURRENT; + h->pkt_type = CICN_PKT_TYPE_CONTROL_REQUEST; + h->pkt_hop_limit = CICN_DEFAULT_HOP_LIMIT; + h->pkt_flags = 0; + h->pkt_hdr_len = sizeof (cicn_packet_hdr_t); + C_PUTINT16 (&h->pkt_len, icn_len); + + /* The message type and length (currently just the name tlv) */ + uint8_t *msg_tlv_p = (uint8_t *) (h + 1); + C_PUTINT16 (&msg_tlv_p[0], CICN_MSG_TYPE_INTEREST); + C_PUTINT16 (&msg_tlv_p[CICN_TLV_TYPE_LEN], CICN_HELLO_NAME_TOT_FLEN); + + /* Copy name tlv, updating adjacency and seq_number components */ + uint8_t *name_tlv_p = &msg_tlv_p[CICN_TLV_HDR_LEN]; + u8 *fid_tlv_p = &name_tlv_p[CICN_HELLO_NAME_CMN_FLEN]; + u8 *seq_tlv_p = &fid_tlv_p[CICN_HELLO_NAME_FACEID_FLEN]; + + clib_memcpy (name_tlv_p, face->fe_ha_name_cmn, CICN_HELLO_NAME_CMN_FLEN); + + cicn_parse_tlv_build (fid_tlv_p, CICN_NAME_COMP, + CICN_HELLO_NAME_FACEID_V_LEN, + &face->fe_ha_fcd_loc.fcd_v[0]); + + cicn_parse_tlv_hdr_build (seq_tlv_p, CICN_NAME_COMP, + CICN_HELLO_NAME_SEQ_V_LEN); + C_PUTINT64 (&seq_tlv_p[CICN_TLV_HDR_LEN], hello_adj->last_sent_seq_num); +} + +/* + * At period expiry, walk through all adjacencies, building and sending + * hello packets. Return number of hello packets sent. + */ +u32 +cicn_hello_periodic (vlib_main_t * vm, vlib_node_runtime_t * node) +{ + cicn_main_t *sm = &cicn_main; + vlib_frame_t *f; + u32 *to_next; + u32 bi0; + u32 active_adjs_found = 0; + int j = 0; + u64 seq_num_gap; + cicn_face_db_entry_t *face_entry; + + /* If no active adjacencies, don't walk array */ + if (sm->n_active_hello_adjs == 0) + { + return (0); + } + + /* Get a frame */ + f = vlib_get_frame_to_node (vm, sm->cicn_hello_next_node_id); + ASSERT (f->n_vectors == 0); + to_next = vlib_frame_vector_args (f); + + for (j = 0; j < CICN_PARAM_FACES_MAX; j++) + { + /* If we have found all the adjs, break */ + if (active_adjs_found >= sm->n_active_hello_adjs) + { + break; + } + + /* If this adj is not active, continue */ + if (!sm->cicn_hello_adjs[j].active) + { + continue; + } + if (cicn_face_entry_find_by_id (j, &face_entry) != AOK) + { + continue; + } + + active_adjs_found++; + + /* Find the gap between the last sent and last acked seq num */ + seq_num_gap = sm->cicn_hello_adjs[j].last_sent_seq_num - + sm->cicn_hello_adjs[j].last_received_seq_num; + /* If we go above the threshold, mark the interface as down */ + if (seq_num_gap >= CICN_PARAM_HELLO_MISSES_DOWN_DFLT) + { + face_entry->flags |= CICN_FACE_FLAG_HELLO_DOWN; + } + vlib_buffer_alloc (vm, &bi0, 1); + + /* Create the icn hello packet in bi0 */ + cicn_hello_packet_build (bi0, &sm->cicn_hello_adjs[j], face_entry); + + cicn_infra_shard_t *wshard = &cicn_infra_shards[vm->cpu_index]; + cicn_face_stats_t *outface_stats = + &wshard->face_stats[cicn_face_db_index (face_entry)]; + outface_stats->orig_interests++; + outface_stats->out_interests++; + + /* Move the buffers to the frame */ + to_next[0] = bi0; + to_next++; + f->n_vectors++; + } + + /* Dispatch the frame to the node */ + vlib_put_frame_to_node (vm, sm->cicn_hello_next_node_id, f); + return (active_adjs_found); +} + +/* + * At cicn enable time, initialize hello's periodic state + * - sm->cicn_hello_next_node_id + * - sm->hello_name (string, wire-format, and initial (2-component) hash + */ +int +cicn_hello_plugin_activation_init (vlib_main_t * vm) +{ + cicn_main_t *sm = &cicn_main; + + /* Up/Down next node id */ + vlib_node_t *next_node = vlib_get_node_by_name (vm, (u8 *) "ip4-lookup"); + sm->cicn_hello_next_node_id = next_node->index; + + /* Set the values of the ICN hello name struct */ + cicn_hello_name_t *hello_name = &sm->hello_name; + cicn_sstrncpy (hello_name->hn_str, CICN_HELLO_NAME_TEMPLATE, + sizeof (hello_name->hn_str)); + + cicn_rd_t cicn_rd; + C_PUTINT16 (&hello_name->hn_wf[0], CICN_TLV_NAME); + hello_name->hn_wf_v_len = + cicn_parse_name_comps_from_str (&hello_name->hn_wf[CICN_TLV_HDR_LEN], + sizeof (hello_name->hn_wf) - + CICN_TLV_HDR_LEN, hello_name->hn_str, + &cicn_rd); + if (hello_name->hn_wf_v_len != CICN_HELLO_NAME_TOT_FLEN - CICN_TLV_HDR_LEN) + { + vlib_cli_output (sm->vlib_main, + "Error parsing hello name template: %s (%d)", + cicn_rd_str (&cicn_rd), hello_name->hn_wf_v_len); + return EINVAL; + } + C_PUTINT16 (&hello_name->hn_wf[CICN_TLV_TYPE_LEN], hello_name->hn_wf_v_len); + + return (AOK); +} + +/* + * The entry-point for the ICN adjacency process, which periodically + * sends adjacency packets. + */ +static uword +icn_hello_process_fn (vlib_main_t * vm, + vlib_node_runtime_t * rt, vlib_frame_t * f) +{ + cicn_main_t *sm = &cicn_main; + f64 up_down_time_remaining; + uword event_type; + cicn_hello_data *d; + uword *event_data = 0; + int i = 0; + cicn_face_db_entry_t *face_entry; + + up_down_time_remaining = sm->cicn_hello_interval; + + /* Loop forever */ + while (1) + { + up_down_time_remaining = vlib_process_wait_for_event_or_clock (vm, + up_down_time_remaining); + /* Get the events (if any) */ + event_type = vlib_process_get_events (vm, &event_data); + if (!sm->is_enabled) + { + ASSERT (vec_len (event_data) == 0); + up_down_time_remaining = sm->cicn_hello_interval; + continue; + } + + switch (event_type) + { + case ~0: + break; + case CICN_HELLO_EVENT_DATA_RCVD: + for (i = 0; i < vec_len (event_data); i++) + { + /* We got a hello Data packet */ + d = (cicn_hello_data *) event_data[i]; + if (sm->cicn_hello_adjs[d->faceid].last_received_seq_num < + d->seq_num) + { + sm->cicn_hello_adjs[d->faceid].last_received_seq_num = + d->seq_num; + /* Find the face and, if down, bring it up */ + if (cicn_face_entry_find_by_id (d->faceid, &face_entry) != + AOK) + { + continue; + } + if (face_entry->flags & CICN_FACE_FLAG_HELLO_DOWN) + { + cicn_face_flags_update (face_entry, 0 /*!set */ , + CICN_FACE_FLAG_HELLO_DOWN); + } + } + } + default: + ; + } + + vec_reset_length (event_data); + + /* peer timeout scan, send up-down Interest */ + if (vlib_process_suspend_time_is_zero (up_down_time_remaining)) + { + u32 adjs_sent = cicn_hello_periodic (vm, rt); + vlib_node_increment_counter (vm, icn_hello_process_node.index, + ICNHELLOPROCESS_ERROR_HELLO_INTERESTS_SENT, + adjs_sent); + + up_down_time_remaining = sm->cicn_hello_interval; + } + } + + /* NOTREACHED */ + return 0; +} + +clib_error_t * +cicn_hello_boot_init (vlib_main_t * vm) +{ + cicn_main_t *sm = &cicn_main; + + sm->n_active_hello_adjs = 0; + sm->cicn_hello_interval_cfgd = 0; + sm->cicn_hello_interval = CICN_PARAM_HELLO_POLL_INTERVAL_DFLT; + + return (0); +} + + +VLIB_REGISTER_NODE (icn_hello_process_node, static) = +{ +.function = icn_hello_process_fn,.type = VLIB_NODE_TYPE_PROCESS,.name = + "icn-hello-process",.process_log2_n_stack_bytes = 16,.n_errors = + ARRAY_LEN (icnhelloprocess_error_strings),.error_strings = + icnhelloprocess_error_strings,}; + +VLIB_INIT_FUNCTION (cicn_hello_boot_init); -- cgit 1.2.3-korg