aboutsummaryrefslogtreecommitdiffstats
path: root/cicn-plugin/cicn/cicn_face.c
diff options
context:
space:
mode:
Diffstat (limited to 'cicn-plugin/cicn/cicn_face.c')
-rw-r--r--cicn-plugin/cicn/cicn_face.c646
1 files changed, 646 insertions, 0 deletions
diff --git a/cicn-plugin/cicn/cicn_face.c b/cicn-plugin/cicn/cicn_face.c
new file mode 100644
index 00000000..2bb90253
--- /dev/null
+++ b/cicn-plugin/cicn/cicn_face.c
@@ -0,0 +1,646 @@
+/*
+ * 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.
+ */
+/*
+ * Implementation if ICN face table
+ */
+#include <vlib/vlib.h>
+#include <vppinfra/error.h>
+#include <vnet/ip/format.h>
+
+#include <cicn/cicn.h>
+
+/*
+ * ICN face underlying swif has a "device class" (e.g. dpdk, af-packet").
+ * Currently, this determines if the device supports dpdk cloning or not.
+ * Retrieve the class index for storage in a newly created face_db entry.
+ */
+static int
+cicn_face_swif_dev_class_index (int swif)
+{
+ int dev_class_index = -1;
+ int unix_rc = AOK;
+
+ vnet_main_t *vnm;
+ vnet_hw_interface_t *hw;
+
+ vnm = vnet_get_main ();
+ hw = vnet_get_sup_hw_interface (vnm, swif);
+ if (hw == NULL)
+ {
+ unix_rc = ENODEV;
+ goto done;
+ }
+ dev_class_index = hw->dev_class_index;
+
+done:
+ return ((dev_class_index >= 0) ? dev_class_index : -unix_rc);
+}
+
+/*
+ * Return the face's swif's device class, for CLI show
+ */
+static const char *
+cicn_face_dev_class_name (const cicn_face_db_entry_t * face)
+{
+
+ vnet_main_t *vnm;
+ vnet_device_class_t *dev_class;
+
+ vnm = vnet_get_main ();
+ dev_class = vnet_get_device_class (vnm, face->swif_dev_class_index);
+ return (dev_class ? dev_class->name : "???");
+}
+
+/*
+ * Utility that adds a new face cache entry
+ */
+static int
+cicn_face_db_add (uint32_t src_addr, uint16_t src_port,
+ uint32_t dest_addr, uint16_t dest_port,
+ int app_face, int swif, int *pfaceid)
+{
+ int ret = 0;
+
+ cicn_face_db_entry_t *ptr;
+ int faceid = 0;
+ int dev_class_index;
+ int is_dpdk_driver;
+ int cloning_supported;
+
+ vnet_device_class_t *dev_class;
+
+ dev_class_index = cicn_face_swif_dev_class_index (swif);
+ if (dev_class_index < 0)
+ {
+ ret = -dev_class_index;
+ goto done;
+ }
+ dev_class = vnet_get_device_class (vnet_get_main (), dev_class_index);
+ if (dev_class == NULL)
+ {
+ ret = ENOENT;
+ goto done;
+ }
+ is_dpdk_driver = !strcmp (dev_class->name, "dpdk");
+ cloning_supported =
+ CICN_FEATURE_VPP_VLIB_CLONING ||
+ (CICN_FEATURE_DPDK_RTEMBUF_CLONING && is_dpdk_driver);
+
+ if (cicn_face_db.entry_count >= CICN_PARAM_FACES_MAX)
+ {
+ ret = ENOMEM;
+ goto done;
+ }
+ ptr = &cicn_face_db.entries[cicn_face_db.entry_count];
+ faceid = cicn_face_db.entry_count + 1; /* Start at one, not zero */
+ cicn_face_db.entry_count++;
+
+ ptr->src_addr.sin_addr.s_addr = src_addr;
+ ptr->src_addr.sin_port = htons (src_port);
+ ptr->dest_addr.sin_addr.s_addr = dest_addr;
+ ptr->dest_addr.sin_port = htons (dest_port);
+ ptr->app_face = app_face;
+ ptr->faceid = faceid;
+ ptr->swif = swif;
+ ptr->swif_dev_class_index = dev_class_index;
+ ptr->swif_is_dpdk_driver = is_dpdk_driver;
+ ptr->swif_cloning_supported = cloning_supported;
+ ptr->flags = CICN_FACE_FLAGS_DEFAULT;
+ ptr->fe_fib_nh_cnt = 0;
+
+
+done:
+ if (pfaceid)
+ {
+ *pfaceid = faceid;
+ }
+
+ return (ret);
+}
+
+/* TODO -- delete face, deactivate/down face apis? */
+
+/*
+ * Locate a face cache entry by face id
+ * TODO: Replace linear scan with faster lookup
+ */
+int
+cicn_face_entry_find_by_id (int id, cicn_face_db_entry_t ** pface)
+{
+ int i, ret = ENOENT;
+ cicn_face_db_entry_t *ptr = cicn_face_db.entries;
+
+ for (i = 0; i < cicn_face_db.entry_count; i++)
+ {
+ if (ptr->faceid == id)
+ {
+
+ /* Don't return/access deleted entries */
+ if (ptr->flags & CICN_FACE_FLAG_DELETED)
+ {
+ goto done;
+ }
+
+ if (pface)
+ {
+ *pface = ptr;
+ }
+
+ ret = AOK;
+ break;
+ }
+
+ ptr++;
+ }
+
+done:
+
+ return (ret);
+}
+
+/*
+ * Find a face cache entry by address, from a packet e.g.
+ */
+int
+cicn_face_entry_find_by_addr (const struct sockaddr_in *src,
+ const struct sockaddr_in *dest,
+ cicn_face_db_entry_t ** pface)
+{
+ int i, ret = ENOENT;
+ cicn_face_db_entry_t *ptr = cicn_face_db.entries;
+
+ for (i = 0; i < cicn_face_db.entry_count; ptr++, i++)
+ {
+ if ((ptr->src_addr.sin_addr.s_addr == src->sin_addr.s_addr) &&
+ (ptr->src_addr.sin_port == src->sin_port) &&
+ (ptr->dest_addr.sin_addr.s_addr == dest->sin_addr.s_addr) &&
+ (ptr->dest_addr.sin_port == dest->sin_port))
+ {
+
+ /* Don't return/access deleted entries */
+ if (ptr->flags & CICN_FACE_FLAG_DELETED)
+ {
+ goto done;
+ }
+
+ if (pface)
+ {
+ *pface = ptr;
+ }
+ ret = AOK;
+ break;
+ }
+ }
+
+done:
+
+ return (ret);
+}
+
+int
+cicn_face_db_index (const cicn_face_db_entry_t * face)
+{
+ return (face - cicn_face_db.entries);
+}
+
+int
+cicn_face_stats_aggregate (const cicn_face_db_entry_t * face,
+ cicn_face_stats_t * face_stats)
+{
+ int fcidx;
+ u32 index = 0;
+ const cicn_face_stats_t *cpu_face_stats;
+
+ memset (face_stats, 0, sizeof (*face_stats));
+
+ fcidx = cicn_face_db_index (face);
+
+ foreach_vlib_main (
+ {
+ cpu_face_stats =
+ &cicn_infra_shards[index].face_stats[fcidx];
+ face_stats->orig_interests +=
+ cpu_face_stats->orig_interests;
+ face_stats->orig_datas += cpu_face_stats->orig_datas;
+ face_stats->orig_naks += cpu_face_stats->orig_naks;
+ face_stats->term_interests +=
+ cpu_face_stats->term_interests;
+ face_stats->term_datas += cpu_face_stats->term_datas;
+ face_stats->term_naks += cpu_face_stats->term_naks;
+ face_stats->in_interests +=
+ cpu_face_stats->in_interests;
+ face_stats->in_datas += cpu_face_stats->in_datas;
+ face_stats->in_naks += cpu_face_stats->in_naks;
+ face_stats->out_interests +=
+ cpu_face_stats->out_interests;
+ face_stats->out_datas += cpu_face_stats->out_datas;
+ face_stats->out_naks += cpu_face_stats->out_naks;
+ index++;
+ }
+ );
+ return (AOK);
+}
+
+/*
+ * Create face, typically while handling cli input. Returns zero
+ * and mails back the faceid on success.
+ */
+int
+cicn_face_add (uint32_t src_addr, uint16_t src_port,
+ uint32_t dest_addr, uint16_t dest_port,
+ int app_face, int swif, int *faceid_p, cicn_rd_t * cicn_rd)
+{
+ int ret = AOK;
+ cicn_rc_e crc = CICN_RC_OK;
+
+ int faceid;
+
+ if (!cicn_infra_fwdr_initialized)
+ {
+ cicn_cli_output ("cicn: fwdr disabled");
+ ret = EINVAL;
+ goto done;
+ }
+ /* check for face already existing */
+ struct sockaddr_in src, dst;
+ src.sin_addr.s_addr = src_addr;
+ src.sin_port = htons (src_port);
+
+ dst.sin_addr.s_addr = dest_addr;
+ dst.sin_port = htons (dest_port);
+ ret = cicn_face_entry_find_by_addr (&src, &dst, NULL /*!pface */ );
+ if (ret == AOK)
+ {
+ ret = EEXIST;
+ goto done;
+ }
+
+ /* TODO -- support delete also? */
+
+ /* TODO -- check face cache for dup before trying to add? */
+
+ /* Add to face cache */
+ ret =
+ cicn_face_db_add (src_addr, src_port, dest_addr, dest_port, app_face,
+ swif, &faceid);
+
+done:
+
+ if ((ret == AOK) && faceid_p)
+ {
+ *faceid_p = faceid;
+ }
+ if (cicn_rd)
+ {
+ cicn_rd_set (cicn_rd, crc, ret);
+ }
+
+ return (ret);
+}
+
+void
+cicn_face_flags_update (cicn_face_db_entry_t * face, int set, u32 uflags)
+{
+ u32 oflags, nflags;
+
+ oflags = nflags = face->flags;
+
+ if (set)
+ {
+ nflags |= uflags;
+ }
+ else
+ {
+ nflags &= ~uflags;
+ }
+
+ if (oflags == nflags)
+ {
+ return;
+ }
+ face->flags = nflags;
+
+ if (oflags & CICN_FACE_FLAGS_DOWN)
+ {
+ if (!(nflags & CICN_FACE_FLAGS_DOWN))
+ {
+ // face => up
+ }
+ }
+ else
+ {
+ if (nflags & CICN_FACE_FLAGS_DOWN)
+ {
+ // face => down
+ }
+ }
+}
+
+/*
+ * based on add being true/false, increment/decrement count of
+ * fib nexthops using face
+ *
+ * return success/error for supplied faceid being valid/invalid
+ */
+int
+cicn_face_fib_nh_cnt_update (int faceid, int add)
+{
+ int ret;
+ cicn_face_db_entry_t *face;
+
+ ret = cicn_face_entry_find_by_id (faceid, &face);
+ if (ret != 0)
+ {
+ goto done;
+ }
+ face->fe_fib_nh_cnt += add ? 1 : -1;
+
+done:
+ return (ret);
+}
+
+/***************************************************************************
+ * CICN_FACE management plane (binary API, debug cli) helper routines
+ ***************************************************************************/
+
+/*
+ * Binary serialization for get face configuration API.
+ */
+vnet_api_error_t
+cicn_face_api_entry_params_serialize (int faceid,
+ vl_api_cicn_api_face_params_get_reply_t
+ * reply)
+{
+ vnet_api_error_t rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+
+ if (!reply)
+ {
+ rv = VNET_API_ERROR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ int i;
+ for (i = 0; i < cicn_face_db.entry_count; i++)
+ {
+ if (i >= CICN_PARAM_FACES_MAX)
+ { // should never happen
+ break;
+ }
+ if (cicn_face_db.entries[i].faceid != faceid)
+ {
+ continue;
+ }
+
+ reply->local_addr =
+ clib_host_to_net_u32 (cicn_face_db.entries[i].src_addr.
+ sin_addr.s_addr);
+ reply->local_port = cicn_face_db.entries[i].src_addr.sin_port;
+
+ reply->remote_addr =
+ clib_host_to_net_u32 (cicn_face_db.entries[i].dest_addr.
+ sin_addr.s_addr);
+ reply->remote_port = cicn_face_db.entries[i].dest_addr.sin_port;
+
+ reply->flags = clib_host_to_net_i32 (cicn_face_db.entries[i].flags);
+
+ reply->sw_interface_id =
+ clib_host_to_net_i32 (cicn_face_db.entries[i].swif);
+
+ rv = CICN_VNET_API_ERROR_NONE;
+ break;
+ }
+
+done:
+ return (rv);
+}
+
+/*
+ * Binary serialization for show faces API.
+ */
+int
+cicn_face_api_entry_props_serialize (vl_api_cicn_api_face_props_get_reply_t *
+ reply)
+{
+ int rv = CICN_VNET_API_ERROR_NONE;
+ int i;
+
+ if (!reply)
+ {
+ rv = VNET_API_ERROR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ for (i = 0; i < cicn_face_db.entry_count; i++)
+ {
+ if (i >= CICN_PARAM_FACES_MAX)
+ { // should never happen
+ break;
+ }
+
+ cicn_face_db_entry_t *face = &cicn_face_db.entries[i];
+ cicn_api_face_entry_t *api_face = (cicn_api_face_entry_t *)
+ (&reply->face[i * sizeof (cicn_api_face_entry_t)]);
+
+ api_face->faceid = clib_host_to_net_i32 (face->faceid);
+
+ api_face->local_addr =
+ clib_host_to_net_u32 (face->src_addr.sin_addr.s_addr);
+ api_face->local_port = face->src_addr.sin_port;
+
+ api_face->remote_addr =
+ clib_host_to_net_u32 (face->dest_addr.sin_addr.s_addr);
+ api_face->remote_port = face->dest_addr.sin_port;
+
+ api_face->flags = clib_host_to_net_i32 (face->flags);
+
+ api_face->sw_interface_id = clib_host_to_net_i32 (face->swif);
+
+ api_face->fib_nhs = clib_host_to_net_u32 (face->fe_fib_nh_cnt);
+ }
+ reply->nentries = clib_host_to_net_i32 (i);
+
+done:
+ return (rv);
+}
+
+
+/*
+ * Binary serialization for face statistics API.
+ */
+int
+cicn_face_api_entry_stats_serialize (int faceid,
+ vl_api_cicn_api_face_stats_get_reply_t *
+ reply)
+{
+ vnet_api_error_t rv = VNET_API_ERROR_NO_SUCH_ENTRY;
+
+ if (!reply)
+ {
+ rv = VNET_API_ERROR_INVALID_ARGUMENT;
+ goto done;
+ }
+
+ int i;
+ for (i = 0; i < cicn_face_db.entry_count; i++)
+ {
+ if (i >= CICN_PARAM_FACES_MAX)
+ { // should never happen
+ break;
+ }
+
+ cicn_face_db_entry_t *face = &cicn_face_db.entries[i];
+
+ if (face->faceid != faceid)
+ {
+ continue;
+ }
+
+ cicn_face_stats_t f_stats;
+
+ reply->faceid = clib_host_to_net_i32 (face->faceid);
+
+ cicn_face_stats_aggregate (&cicn_face_db.entries[i], &f_stats);
+
+ reply->orig_interests = clib_host_to_net_u64 (f_stats.orig_interests);
+ reply->orig_datas = clib_host_to_net_u64 (f_stats.orig_datas);
+ reply->orig_naks = clib_host_to_net_u64 (f_stats.orig_naks);
+ reply->term_interests = clib_host_to_net_u64 (f_stats.term_interests);
+ reply->term_datas = clib_host_to_net_u64 (f_stats.term_datas);
+ reply->term_naks = clib_host_to_net_u64 (f_stats.term_naks);
+ reply->in_interests = clib_host_to_net_u64 (f_stats.in_interests);
+ reply->in_datas = clib_host_to_net_u64 (f_stats.in_datas);
+ reply->in_naks = clib_host_to_net_u64 (f_stats.in_naks);
+ reply->out_interests = clib_host_to_net_u64 (f_stats.out_interests);
+ reply->out_datas = clib_host_to_net_u64 (f_stats.out_datas);
+ reply->out_naks = clib_host_to_net_u64 (f_stats.out_naks);
+
+ rv = CICN_VNET_API_ERROR_NONE;
+ break;
+ }
+
+done:
+ return (rv);
+}
+
+/*
+ * CLI show output for faces. if 'faceid' >= 0, just show a single face
+ */
+int
+cicn_face_show (int faceid_arg, int detail_p, int internal_p)
+{
+ int ret = 0;
+ int i;
+ u8 *sbuf = 0, *dbuf = 0;
+
+ cicn_cli_output ("Faces:");
+
+ for (i = 0; i < cicn_face_db.entry_count; i++)
+ {
+ cicn_face_db_entry_t *face = &cicn_face_db.entries[i];
+ int efaceid = face->faceid;
+ if ((faceid_arg >= 0) && (faceid_arg != efaceid))
+ {
+ continue;
+ }
+
+ vec_reset_length (sbuf);
+ sbuf = format (sbuf, "%U", format_ip4_address,
+ &face->src_addr.sin_addr);
+ vec_terminate_c_string (sbuf);
+
+ vec_reset_length (dbuf);
+ dbuf = format (dbuf, "%U", format_ip4_address,
+ &face->dest_addr.sin_addr);
+ vec_terminate_c_string (dbuf);
+
+ char *if_status = "unknown";
+ if (face->flags & CICN_FACE_FLAG_DELETED)
+ {
+ if_status = "DELETED";
+ }
+ else if (face->flags & CICN_FACE_FLAG_ADMIN_DOWN)
+ {
+ if_status = "admin-down";
+ }
+ else if (face->flags & CICN_FACE_FLAGS_DOWN)
+ {
+ if_status = "oper-down";
+ }
+ else
+ {
+ if_status = "up";
+ }
+ cicn_cli_output (" Face %d: %s:%d <-> %s:%d (swif %d)",
+ face->faceid, sbuf, ntohs (face->src_addr.sin_port),
+ dbuf, ntohs (face->dest_addr.sin_port), face->swif);
+
+ cicn_cli_output ("\tFace Type:%s, State:%s, FIB_NHs:%d, Class:%s(%s)",
+ face->app_face ? "app" : "peer", if_status,
+ face->fe_fib_nh_cnt, cicn_face_dev_class_name (face),
+ face->swif_cloning_supported ? "clone" : "copy");
+
+ // TODO: More output.
+ cicn_main_t *sm = &cicn_main;
+ if (sm->cicn_hello_adjs[efaceid].active)
+ {
+ cicn_cli_output
+ ("\t%-14.14s State:enabled,%s [last_sent:%lu, last_rcvd:%lu]",
+ "Hello Proto:",
+ (face->flags & CICN_FACE_FLAG_HELLO_DOWN) ? "down" : "up",
+ sm->cicn_hello_adjs[efaceid].last_sent_seq_num,
+ sm->cicn_hello_adjs[efaceid].last_received_seq_num);
+ }
+ else
+ {
+ cicn_cli_output ("\tHello Protocol: State:disabled");
+ }
+
+ cicn_face_stats_t face_stats;
+ cicn_face_stats_aggregate (face, &face_stats);
+
+#define CICN_SHOW_MSGS_FMT "\t%-14.14s Interests:%lu, Data:%lu, Naks:%lu"
+ cicn_cli_output (CICN_SHOW_MSGS_FMT, "Originated:",
+ face_stats.orig_interests, face_stats.orig_datas,
+ face_stats.orig_naks);
+
+ cicn_cli_output (CICN_SHOW_MSGS_FMT, "Terminated:",
+ face_stats.term_interests, face_stats.term_datas,
+ face_stats.term_naks);
+
+ cicn_cli_output (CICN_SHOW_MSGS_FMT, "Received:",
+ face_stats.in_interests, face_stats.in_datas,
+ face_stats.in_naks);
+
+ cicn_cli_output (CICN_SHOW_MSGS_FMT, "Sent:",
+ face_stats.out_interests, face_stats.out_datas,
+ face_stats.out_naks);
+
+ if (faceid_arg >= 0)
+ { // found it
+ break;
+ }
+ }
+
+ if (sbuf)
+ {
+ vec_free (sbuf);
+ }
+ if (dbuf)
+ {
+ vec_free (dbuf);
+ }
+
+ return (ret);
+}