From 704381d7bac04215ef270359f34658856c00d9a0 Mon Sep 17 00:00:00 2001 From: Sachin Saxena Date: Thu, 15 Jun 2017 14:34:30 +0530 Subject: Introducing ODP plugin node Change-Id: I364fa14ade5282ec828662894041f9cc784ace7c Signed-off-by: srsurend Signed-off-by: sachin saxena --- src/plugins/odp/odp_packet.c | 363 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100755 src/plugins/odp/odp_packet.c (limited to 'src/plugins/odp/odp_packet.c') diff --git a/src/plugins/odp/odp_packet.c b/src/plugins/odp/odp_packet.c new file mode 100755 index 00000000..a8c606d8 --- /dev/null +++ b/src/plugins/odp/odp_packet.c @@ -0,0 +1,363 @@ +/* + *------------------------------------------------------------------ + * Copyright (c) 2016 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 +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 +odp_packet_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, + u32 flags) +{ + /* nothing for now */ + return 0; +} + +/** + * Drop packets which input parsing marked as containing errors. + * + * Frees packets with error and modifies pkt_tbl[] to only contain packets with + * no detected errors. + * + * @param pkt_tbl Array of packet + * @param len Length of pkt_tbl[] + * + * @return Number of packets with no detected error + */ +u32 +drop_err_pkts(odp_packet_t pkt_tbl[], unsigned len) +{ + odp_packet_t pkt; + unsigned pkt_cnt = len; + unsigned i, j; + + for (i = 0, j = 0; i < len; ++i) + { + pkt = pkt_tbl[i]; + + if (odp_unlikely(odp_packet_has_error(pkt))) + { + odp_packet_free(pkt); /* Drop */ + pkt_cnt--; + } + else if (odp_unlikely(i != j++)) + { + pkt_tbl[j-1] = pkt; + } + } + + return pkt_cnt; +} + +static odp_pktio_t +create_pktio(const char *dev, odp_pool_t pool, u32 mode) +{ + odp_pktio_t pktio; + int ret; + odp_pktio_param_t pktio_param; + odp_pktin_queue_param_t pktin_param; + + odp_pktio_param_init(&pktio_param); + + switch(mode) + { + case APPL_MODE_PKT_BURST: + pktio_param.in_mode = ODP_PKTIN_MODE_DIRECT; + break; + case APPL_MODE_PKT_QUEUE: + pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE; + break; + case APPL_MODE_PKT_SCHED: + pktio_param.in_mode = ODP_PKTIN_MODE_SCHED; + break; + default: + clib_warning("Invalid mode\n"); + } + + /* Open a packet IO instance */ + pktio = odp_pktio_open(dev, pool, &pktio_param); + + if (pktio == ODP_PKTIO_INVALID) + { + clib_warning("Error: pktio create failed for %s",dev); + } + + odp_pktin_queue_param_init(&pktin_param); + + if (mode == APPL_MODE_PKT_SCHED) + pktin_param.queue_param.sched.sync = ODP_SCHED_SYNC_ATOMIC; + + if (odp_pktin_queue_config(pktio, &pktin_param)) + { + clib_warning("Error: pktin config failed"); + } + + if (odp_pktout_queue_config(pktio, NULL)) + { + clib_warning("Error: pktout config failed"); + } + + ret = odp_pktio_start(pktio); + if (ret != 0) + { + clib_warning("Error: unable to start"); + } + + return pktio; +} + +int +odp_worker_thread_enable () +{ + + /*If worker threads are enabled, switch to polling mode */ + foreach_vlib_main (( + { + vlib_node_set_state (this_vlib_main, + odp_packet_input_node.index, + VLIB_NODE_STATE_POLLING); + })); + return 0; +} + +int +odp_worker_thread_disable () +{ + foreach_vlib_main (( + { + vlib_node_set_state (this_vlib_main, + odp_packet_input_node.index, + VLIB_NODE_STATE_DISABLED); + })); + + return 0; +} + +u32 +odp_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, + u32 * sw_if_index , u32 mode) +{ + odp_packet_main_t *om = &odp_packet_main; + int ret = 0; + odp_packet_if_t *oif = 0; + u8 hw_addr[6]; + clib_error_t *error = 0; + vnet_sw_interface_t *sw; + vnet_main_t *vnm = vnet_get_main (); + uword *p; + u8 *host_if_name_dup=vec_dup(host_if_name); + vlib_thread_main_t *tm= vlib_get_thread_main(); + + p = mhash_get (&om->if_index_by_host_if_name, host_if_name); + if (p) + return VNET_API_ERROR_SUBIF_ALREADY_EXISTS; + + pool_get (om->interfaces, oif); + oif->if_index = oif - om->interfaces; + oif->host_if_name = host_if_name_dup; + oif->per_interface_next_index= ~0; + + /* Create a pktio instance */ + oif->pktio=create_pktio((char*)host_if_name, om->pool, mode); + oif->mode=mode; + om->if_count++; + + if (tm->n_vlib_mains > 1) + { + oif->lockp = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES, + CLIB_CACHE_LINE_BYTES); + memset ((void *) oif->lockp, 0, CLIB_CACHE_LINE_BYTES); + } + + /*use configured or generate random MAC address */ + if (hw_addr_set) + clib_memcpy (hw_addr, hw_addr_set, 6); + else + { + f64 now = vlib_time_now (vm); + u32 rnd; + rnd = (u32) (now * 1e6); + rnd = random_u32 (&rnd); + + clib_memcpy (hw_addr + 2, &rnd, sizeof (rnd)); + hw_addr[0] = 2; + hw_addr[1] = 0xfe; + } + + error = ethernet_register_interface (vnm, odp_packet_device_class.index, + oif->if_index, hw_addr, &oif->hw_if_index, odp_packet_eth_flag_change); + + if (error) + { + memset (oif, 0, sizeof (*oif)); + pool_put (om->interfaces, oif); + clib_error_report (error); + ret = VNET_API_ERROR_SYSCALL_ERROR_1; + goto error; + } + + sw = vnet_get_hw_sw_interface (vnm, oif->hw_if_index); + oif->sw_if_index = sw->sw_if_index; + + vnet_hw_interface_set_flags (vnm, oif->hw_if_index, + VNET_HW_INTERFACE_FLAG_LINK_UP); + + mhash_set_mem (&om->if_index_by_host_if_name, host_if_name_dup, &oif->if_index, + 0); + if (sw_if_index) + *sw_if_index = oif->sw_if_index; + + if (tm->n_vlib_mains > 1 && pool_elts (om->interfaces) == 1) + { + /*Fixme :Workers support commented for now as vlib_buffer not thread safe*/ + //odp_worker_thread_enable (); + } + else + { + vlib_node_set_state (vm, odp_packet_input_node.index, + VLIB_NODE_STATE_POLLING); + } + return 0; + + error: + vec_free (host_if_name_dup); + + return ret; +} + +u32 +odp_packet_delete_if (vlib_main_t * vm, u8 * host_if_name) +{ + vnet_main_t *vnm = vnet_get_main (); + odp_packet_main_t *om = &odp_packet_main; + odp_packet_if_t *oif = 0; + uword *p; + vlib_thread_main_t *tm= vlib_get_thread_main(); + + p = mhash_get (&om->if_index_by_host_if_name, host_if_name); + + if (p == NULL) + { + clib_warning ("Host interface %s does not exist", host_if_name); + return VNET_API_ERROR_SYSCALL_ERROR_1; + } + + oif = pool_elt_at_index (om->interfaces, p[0]); + vnet_hw_interface_set_flags (vnm, oif->hw_if_index, 0); + + om->if_count--; + + odp_pktio_stop(odp_pktio_lookup((char*)host_if_name)); + odp_pktio_close(odp_pktio_lookup((char*)host_if_name)); + + vec_free (oif->host_if_name); + oif->host_if_name = NULL; + + mhash_unset (&om->if_index_by_host_if_name, host_if_name, &oif->if_index); + ethernet_delete_interface (vnm, oif->hw_if_index); + + pool_put(om->interfaces, oif); + + if (tm->n_vlib_mains > 1 && pool_elts (om->interfaces) == 0) + { + odp_pool_destroy(om->pool); + /*Fixme :Workers support commented for now*/ + // odp_worker_thread_disable (); + } + + return 0; + +} + +static clib_error_t * +odp_packet_init (vlib_main_t * vm) +{ + odp_packet_main_t *om = &odp_packet_main; + vlib_thread_main_t *tm = vlib_get_thread_main (); + vlib_thread_registration_t *tr; + uword *p; + odp_platform_init_t platform_params; + odp_pool_param_t params; + + memset(om, 0, sizeof(odp_packet_main_t)); + om->input_cpu_first_index = 0; + om->input_cpu_count = 1; + om->if_count = 0; + memset(&platform_params, 0, sizeof(platform_params)); + + if (odp_init_global(&om->instance, NULL, &platform_params)) + clib_warning("Error:ODP global init failed"); + + if (odp_init_local(om->instance, ODP_THREAD_CONTROL) != 0) + { + clib_warning("Error: ODP local init failed"); + odp_term_global(om->instance); + + } + /* Create packet pool */ + odp_pool_param_init(¶ms); + params.pkt.seg_len = SHM_PKT_POOL_BUF_SIZE; + params.pkt.len = SHM_PKT_POOL_BUF_SIZE; + params.type = ODP_POOL_PACKET; + params.pkt.num = SHM_PKT_POOL_NB_PKTS; + + om->pool = odp_pool_create(SHM_PKT_POOL_NAME, ¶ms); + + if (om->pool == ODP_POOL_INVALID) + { + clib_warning("Error: packet pool create failed"); + } + + /* find out which cpus will be used for input */ + p = hash_get_mem (tm->thread_registrations_by_name, "workers"); + tr = p ? (vlib_thread_registration_t *) p[0] : 0; + + if (tr && tr->count > 0) + { + om->input_cpu_first_index = tr->first_index; + om->input_cpu_count = tr->count; + } + + mhash_init_vec_string (&om->if_index_by_host_if_name, sizeof (uword)); + + vec_validate_aligned (om->rx_buffers, tm->n_vlib_mains - 1, + CLIB_CACHE_LINE_BYTES); + return 0; +} + +VLIB_INIT_FUNCTION (odp_packet_init); + +/* *INDENT-OFF* */ +VLIB_PLUGIN_REGISTER () = { + .version = VPP_BUILD_VER, + .description = "ODP", +}; +/* *INDENT-ON* */ + +/* + * fd.io coding-style-patch-verification: ON + * + * Local Variables: + * eval: (c-set-style "gnu") + * End: + */ -- cgit 1.2.3-korg