X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=VNFs%2FDPPD-PROX%2Fmain.c;h=61abe6e61f1fa6e461bdd60fad4c225690787e8a;hb=090efc9c81c8b1943d162249d965a3e40502d50e;hp=2c8517f0a64c4afe3c84088beeef5cb127cc4164;hpb=6401ebd2b472a2402b640f4e8c773cc3d097093f;p=samplevnf.git diff --git a/VNFs/DPPD-PROX/main.c b/VNFs/DPPD-PROX/main.c index 2c8517f0..61abe6e6 100644 --- a/VNFs/DPPD-PROX/main.c +++ b/VNFs/DPPD-PROX/main.c @@ -1,5 +1,5 @@ /* -// Copyright (c) 2010-2017 Intel Corporation +// Copyright (c) 2010-2020 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,7 @@ #endif uint8_t lb_nb_txrings = 0xff; +extern const char *git_version; struct rte_ring *ctrl_rings[RTE_MAX_LCORE*MAX_TASKS_PER_CORE]; static void __attribute__((noreturn)) prox_usage(const char *prgname) @@ -114,7 +116,7 @@ static void check_mixed_normal_pipeline(void) } } -static void check_zero_rx(void) +static void check_no_rx(void) { struct lcore_cfg *lconf = NULL; struct task_args *targ; @@ -127,12 +129,34 @@ static void check_zero_rx(void) } } +static void check_nb_mbuf(void) +{ + struct lcore_cfg *lconf = NULL; + struct task_args *targ = NULL; + uint8_t port_id; + int n_txd = 0, n_rxd = 0; + + while (core_targ_next(&lconf, &targ, 0) == 0) { + for (uint8_t i = 0; i < targ->nb_txports; ++i) { + port_id = targ->tx_port_queue[i].port; + n_txd = prox_port_cfg[port_id].n_txd; + } + for (uint8_t i = 0; i < targ->nb_rxports; ++i) { + port_id = targ->rx_port_queue[i].port; + n_rxd = prox_port_cfg[port_id].n_rxd; + } + if (targ->nb_mbuf <= n_rxd + n_txd + targ->nb_cache_mbuf + MAX_PKT_BURST) { + plog_warn("Core %d, task %d might not have enough mbufs (%d) to support %d txd, %d rxd and %d cache_mbuf\n", + lconf->id, targ->id, targ->nb_mbuf, n_txd, n_rxd, targ->nb_cache_mbuf); + } + } +} + static void check_missing_rx(void) { struct lcore_cfg *lconf = NULL, *rx_lconf = NULL, *tx_lconf = NULL; struct task_args *targ, *rx_targ = NULL, *tx_targ = NULL; - struct prox_port_cfg *port; - uint8_t port_id, rx_port_id, ok; + uint8_t port_id, rx_port_id, ok, l3, ndp; while (core_targ_next(&lconf, &targ, 0) == 0) { PROX_PANIC((targ->flags & TASK_ARG_RX_RING) && targ->rx_rings[0] == 0 && !targ->tx_opt_ring_task, @@ -145,12 +169,17 @@ static void check_missing_rx(void) lconf = NULL; while (core_targ_next(&lconf, &targ, 0) == 0) { - if (strcmp(targ->sub_mode_str, "l3") != 0) + l3 = ndp = 0; + if (strcmp(targ->sub_mode_str, "l3") == 0) + l3 = 1; + else if (strcmp(targ->sub_mode_str, "ndp") == 0) + ndp = 1; + else continue; - PROX_PANIC((targ->nb_rxports == 0) && (targ->nb_txports == 0), "L3 task must have a RX or a TX port\n"); - // If the L3 sub_mode receives from a port, check that there is at least one core/task - // transmitting to this port in L3 sub_mode + PROX_PANIC((targ->nb_rxports == 0) && (targ->nb_txports == 0), "L3/NDP task must have a RX or a TX port\n"); + // If the L3/NDP sub_mode receives from a port, check that there is at least one core/task + // transmitting to this port in L3/NDP sub_mode for (uint8_t i = 0; i < targ->nb_rxports; ++i) { rx_port_id = targ->rx_port_queue[i].port; ok = 0; @@ -158,42 +187,48 @@ static void check_missing_rx(void) while (core_targ_next(&tx_lconf, &tx_targ, 0) == 0) { if ((port_id = tx_targ->tx_port_queue[0].port) == OUT_DISCARD) continue; - if ((rx_port_id == port_id) && (tx_targ->flags & TASK_ARG_L3)){ + if ((rx_port_id == port_id) && + ( ((tx_targ->flags & TASK_ARG_L3) && l3) || + ((tx_targ->flags & TASK_ARG_NDP) && ndp) ) ) { ok = 1; break; } } - PROX_PANIC(ok == 0, "RX L3 sub mode for port %d on core %d task %d, but no core/task transmitting on that port\n", rx_port_id, lconf->id, targ->id); + PROX_PANIC(ok == 0, "RX %s sub mode for port %d on core %d task %d, but no core/task transmitting on that port\n", l3 ? "l3":"ndp", rx_port_id, lconf->id, targ->id); } - // If the L3 sub_mode transmits to a port, check that there is at least one core/task - // receiving from that port in L3 sub_mode. + // If the L3/NDP sub_mode transmits to a port, check that there is at least one core/task + // receiving from that port in L3/NDP sub_mode. if ((port_id = targ->tx_port_queue[0].port) == OUT_DISCARD) continue; rx_lconf = NULL; ok = 0; - plog_info("\tCore %d task %d transmitting to port %d in L3 mode\n", lconf->id, targ->id, port_id); + plog_info("\tCore %d task %d transmitting to port %d in %s submode\n", lconf->id, targ->id, port_id, l3 ? "l3":"ndp"); while (core_targ_next(&rx_lconf, &rx_targ, 0) == 0) { for (uint8_t i = 0; i < rx_targ->nb_rxports; ++i) { rx_port_id = rx_targ->rx_port_queue[i].port; - if ((rx_port_id == port_id) && (rx_targ->flags & TASK_ARG_L3)){ + if ((rx_port_id == port_id) && + ( ((rx_targ->flags & TASK_ARG_L3) && l3) || + ((rx_targ->flags & TASK_ARG_NDP) && ndp) ) ){ ok = 1; break; } } if (ok == 1) { - plog_info("\tCore %d task %d has found core %d task %d receiving from port %d\n", lconf->id, targ->id, rx_lconf->id, rx_targ->id, port_id); + plog_info("\tCore %d task %d has found core %d task %d receiving from port %d in %s submode\n", lconf->id, targ->id, rx_lconf->id, rx_targ->id, port_id, + ((rx_targ->flags & TASK_ARG_L3) && l3) ? "l3":"ndp"); break; } } - PROX_PANIC(ok == 0, "L3 sub mode for port %d on core %d task %d, but no core/task receiving on that port\n", port_id, lconf->id, targ->id); + PROX_PANIC(ok == 0, "%s sub mode for port %d on core %d task %d, but no core/task receiving on that port\n", l3 ? "l3":"ndp", port_id, lconf->id, targ->id); } } static void check_cfg_consistent(void) { + check_nb_mbuf(); check_missing_rx(); - check_zero_rx(); + check_no_rx(); check_mixed_normal_pipeline(); } @@ -224,6 +259,21 @@ static int chain_flag_state(struct task_args *targ, uint64_t flag, int is_set) return 0; } +static int chain_flag_always_set(struct task_args *targ, uint64_t flag) +{ + return (!chain_flag_state(targ, flag, 0)); +} + +static int chain_flag_never_set(struct task_args *targ, uint64_t flag) +{ + return (!chain_flag_state(targ, flag, 1)); +} + +static int chain_flag_sometimes_set(struct task_args *targ, uint64_t flag) +{ + return (chain_flag_state(targ, flag, 1)); +} + static void configure_if_tx_queues(struct task_args *targ, uint8_t socket) { uint8_t if_port; @@ -247,44 +297,68 @@ static void configure_if_tx_queues(struct task_args *targ, uint8_t socket) prox_port_cfg[if_port].n_txq = 1; targ->tx_port_queue[i].queue = 0; } - /* Set the ETH_TXQ_FLAGS_NOREFCOUNT flag if none of - the tasks up to the task transmitting to the port - does not use refcnt. */ - if (!chain_flag_state(targ, TASK_FEATURE_TXQ_FLAGS_REFCOUNT, 1)) { - prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOREFCOUNT; - plog_info("\t\tEnabling No refcnt on port %d\n", if_port); - } - else { - plog_info("\t\tRefcnt used on port %d\n", if_port); - } - /* By default OFFLOAD is enabled, but if the whole chain has NOOFFLOADS set all the way until the first task that receives from a port, it will be disabled for the destination port. */ - if (chain_flag_state(targ, TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS, 1)) { +#if RTE_VERSION < RTE_VERSION_NUM(18,8,0,1) + if (chain_flag_always_set(targ, TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS)) { prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOOFFLOADS; - plog_info("\t\tDisabling TX offloads on port %d\n", if_port); - } else { - plog_info("\t\tEnabling TX offloads on port %d\n", if_port); } - - /* By default NOMULTSEGS is disabled, as drivers/NIC might split packets on RX - It should only be enabled when we know for sure that the RX does not split packets. - Set the ETH_TXQ_FLAGS_NOMULTSEGS flag if none of the tasks up to the task - transmitting to the port does not use multsegs. */ - if (!chain_flag_state(targ, TASK_FEATURE_TXQ_FLAGS_NOMULTSEGS, 0)) { - prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOMULTSEGS; - plog_info("\t\tEnabling No MultiSegs on port %d\n", if_port); - } - else { - plog_info("\t\tMultiSegs used on port %d\n", if_port); +#else + if (chain_flag_always_set(targ, TASK_FEATURE_TXQ_FLAGS_NOOFFLOADS)) { + prox_port_cfg[if_port].requested_tx_offload &= ~(RTE_ETH_TX_OFFLOAD_IPV4_CKSUM | RTE_ETH_TX_OFFLOAD_UDP_CKSUM); } +#endif } } static void configure_if_rx_queues(struct task_args *targ, uint8_t socket) { + struct prox_port_cfg *port; + uint8_t port_used_counter[PROX_MAX_PORTS] = {0}; + bool multiple_port_reference = false; + uint8_t total_number_of_queues = 0; + // Check how many times a port is referenced for this task + for (uint8_t i = 0; i < targ->nb_rxports; i++) { + uint8_t if_port = targ->rx_port_queue[i].port; + port_used_counter[if_port]++; + if (port_used_counter[if_port] > 1) { + multiple_port_reference = true; + port = &prox_port_cfg[if_port]; + PROX_PANIC((port->all_rx_queues), "Multiple queues defined in rx port, but all_rx_queues also set for port %s\n", port->names[0]); + } + } + // If only referenced once, it is possible that we want to use all queues + // Therefore we will check all_rx_queues for that port + if (!multiple_port_reference) { + for (uint8_t i = 0; i < PROX_MAX_PORTS; i++) { + uint8_t if_port = targ->rx_port_queue[i].port; + if (port_used_counter[if_port]) { + port = &prox_port_cfg[if_port]; + if (port->all_rx_queues) { + port_used_counter[if_port] = port->max_rxq; + total_number_of_queues += port->max_rxq; + plog_info("\tall_rx_queues for Port %s: %u rx_queues will be applied\n", port->names[0], port_used_counter[if_port]); + } + } + } + } + if (total_number_of_queues) { + PROX_PANIC((total_number_of_queues > PROX_MAX_PORTS), "%u queues using the all_rx_queues. PROX_MAX_PORTS is set to %u\n", total_number_of_queues, PROX_MAX_PORTS); + uint8_t index = 0; + for (uint8_t i = 0; i < PROX_MAX_PORTS; i++) { + if (port_used_counter[i]) { + for (uint8_t j = 0; j < port_used_counter[i]; j++) { + targ->rx_port_queue[index].port = i; + index ++; + } + port = &prox_port_cfg[i]; + plog_info("\t\tConfiguring task to use port %s with %u rx_queues\n", port->names[0], port_used_counter[i]); + } + } + targ->nb_rxports = index; + } for (int i = 0; i < targ->nb_rxports; i++) { uint8_t if_port = targ->rx_port_queue[i].port; @@ -292,18 +366,26 @@ static void configure_if_rx_queues(struct task_args *targ, uint8_t socket) return; } - PROX_PANIC(!prox_port_cfg[if_port].active, "Port %u not used, aborting...\n", if_port); + port = &prox_port_cfg[if_port]; + PROX_PANIC(!port->active, "Port %u not used, aborting...\n", if_port); - if(prox_port_cfg[if_port].rx_ring[0] != '\0') { - prox_port_cfg[if_port].n_rxq = 0; + if(port->rx_ring[0] != '\0') { + port->n_rxq = 0; } - targ->rx_port_queue[i].queue = prox_port_cfg[if_port].n_rxq; - prox_port_cfg[if_port].pool[targ->rx_port_queue[i].queue] = targ->pool; - prox_port_cfg[if_port].pool_size[targ->rx_port_queue[i].queue] = targ->nb_mbuf - 1; - prox_port_cfg[if_port].n_rxq++; + // If the mbuf size (of the rx task) is not big enough, we might receive multiple segments + // This is usually the case when setting a big mtu size i.e. enabling jumbo frames. + // If the packets get transmitted, then multi segments will have to be enabled on the TX port + uint16_t max_frame_size = port->mtu + PROX_RTE_ETHER_HDR_LEN + PROX_RTE_ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE; + if (max_frame_size + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM > targ->mbuf_size) { + targ->task_init->flag_features |= TASK_FEATURE_TXQ_FLAGS_MULTSEGS; + } + targ->rx_port_queue[i].queue = port->n_rxq; + port->pool[targ->rx_port_queue[i].queue] = targ->pool; + port->pool_size[targ->rx_port_queue[i].queue] = targ->nb_mbuf - 1; + port->n_rxq++; - int dsocket = prox_port_cfg[if_port].socket; + int dsocket = port->socket; if (dsocket != -1 && dsocket != socket) { plog_warn("RX core on socket %d while device on socket %d\n", socket, dsocket); } @@ -319,8 +401,64 @@ static void configure_if_queues(void) while (core_targ_next(&lconf, &targ, 0) == 0) { socket = rte_lcore_to_socket_id(lconf->id); - configure_if_tx_queues(targ, socket); configure_if_rx_queues(targ, socket); + configure_if_tx_queues(targ, socket); + } +} + +static void configure_tx_queue_flags(void) +{ + struct lcore_cfg *lconf = NULL; + struct task_args *targ; + uint8_t socket; + uint8_t if_port; + + while (core_targ_next(&lconf, &targ, 0) == 0) { + socket = rte_lcore_to_socket_id(lconf->id); + for (uint8_t i = 0; i < targ->nb_txports; ++i) { + if_port = targ->tx_port_queue[i].port; +#if RTE_VERSION < RTE_VERSION_NUM(18,8,0,1) + /* Set the ETH_TXQ_FLAGS_NOREFCOUNT flag if none of + the tasks up to the task transmitting to the port + use refcnt. */ + if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_REFCOUNT)) { + prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOREFCOUNT; + } +#else + /* Set the RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE flag if none of + the tasks up to the task transmitting to the port + use refcnt and per-queue all mbufs comes from the same mempool. */ + if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_REFCOUNT)) { + if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_MULTIPLE_MEMPOOL)) + prox_port_cfg[if_port].requested_tx_offload |= RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE; + } +#endif + } + } +} + +static void configure_multi_segments(void) +{ + struct lcore_cfg *lconf = NULL; + struct task_args *targ; + uint8_t if_port; + + while (core_targ_next(&lconf, &targ, 0) == 0) { + for (uint8_t i = 0; i < targ->nb_txports; ++i) { + if_port = targ->tx_port_queue[i].port; + // Multi segment is disabled for most tasks. It is only enabled for tasks requiring big packets. +#if RTE_VERSION < RTE_VERSION_NUM(18,8,0,1) + // We can only enable "no multi segment" if no such task exists in the chain of tasks. + if (chain_flag_never_set(targ, TASK_FEATURE_TXQ_FLAGS_MULTSEGS)) { + prox_port_cfg[if_port].tx_conf.txq_flags |= ETH_TXQ_FLAGS_NOMULTSEGS; + } +#else + // We enable "multi segment" if at least one task requires it in the chain of tasks. + if (chain_flag_sometimes_set(targ, TASK_FEATURE_TXQ_FLAGS_MULTSEGS)) { + prox_port_cfg[if_port].requested_tx_offload |= RTE_ETH_TX_OFFLOAD_MULTI_SEGS; + } +#endif + } } } @@ -441,7 +579,7 @@ static struct rte_ring *init_ring_between_tasks(struct lcore_cfg *lconf, struct starg->ctrl_plane_ring = ring; } - plog_info("\t\tCore %u task %u to -> core %u task %u ctrl_ring %s %p %s\n", + plog_info("\t\t\tCore %u task %u to -> core %u task %u ctrl_ring %s %p %s\n", lconf->id, starg->id, ct.core, ct.task, ct.type == CTRL_TYPE_PKT? "pkt" : "msg", ring, ring->name); ris->n_ctrl_rings++; @@ -500,6 +638,8 @@ static struct rte_ring *init_ring_between_tasks(struct lcore_cfg *lconf, struct PROX_ASSERT(dtarg->nb_rxrings < MAX_RINGS_PER_TASK); dtarg->rx_rings[dtarg->nb_rxrings] = ring; ++dtarg->nb_rxrings; + if (dtarg->nb_rxrings > 1) + dtarg->task_init->flag_features |= TASK_FEATURE_TXQ_FLAGS_MULTIPLE_MEMPOOL; } dtarg->nb_slave_threads = starg->core_task_set[idx].n_elems; dtarg->lb_friend_core = lconf->id; @@ -543,7 +683,7 @@ static void init_rings(void) lconf = NULL; struct prox_port_cfg *port; while (core_targ_next(&lconf, &starg, 1) == 0) { - if ((starg->task_init) && (starg->flags & TASK_ARG_L3)) { + if ((starg->task_init) && (starg->flags & (TASK_ARG_L3|TASK_ARG_NDP))) { struct core_task ct; ct.core = prox_cfg.master; ct.task = 0; @@ -552,7 +692,7 @@ static void init_rings(void) ct.core = lconf->id; ct.task = starg->id;; - struct rte_ring *tx_ring = init_ring_between_tasks(lcore_cfg, lcore_cfg[prox_cfg.master].targs, ct, 0, 0, &ris); + struct rte_ring *tx_ring = init_ring_between_tasks(&lcore_cfg[prox_cfg.master], lcore_cfg[prox_cfg.master].targs, ct, 0, 0, &ris); } } } @@ -562,13 +702,14 @@ static void shuffle_mempool(struct rte_mempool* mempool, uint32_t nb_mbuf) struct rte_mbuf** pkts = prox_zmalloc(nb_mbuf * sizeof(*pkts), rte_socket_id()); uint64_t got = 0; - while (rte_mempool_get_bulk(mempool, (void**)(pkts + got), 1) == 0) + while ((got < nb_mbuf) && (rte_mempool_get_bulk(mempool, (void**)(pkts + got), 1) == 0)) ++got; + nb_mbuf = got; while (got) { int idx; do { - idx = rand() % nb_mbuf - 1; + idx = rand() % nb_mbuf; } while (pkts[idx] == 0); rte_mempool_put_bulk(mempool, (void**)&pkts[idx], 1); @@ -578,6 +719,50 @@ static void shuffle_mempool(struct rte_mempool* mempool, uint32_t nb_mbuf) prox_free(pkts); } +static void set_mbuf_size(struct task_args *targ) +{ + /* mbuf size can be set + * - from config file (highest priority, overwriting any other config) - should only be used as workaround + * - defaulted to MBUF_SIZE. + * Except if set explicitely, ensure that size is big enough for vmxnet3 driver + */ + if (targ->mbuf_size) + return; + + targ->mbuf_size = MBUF_SIZE; + struct prox_port_cfg *port; + uint16_t max_frame_size = 0, min_buffer_size = 0; + int i40e = 0; + for (int i = 0; i < targ->nb_rxports; i++) { + uint8_t if_port = targ->rx_port_queue[i].port; + + if (if_port == OUT_DISCARD) { + continue; + } + port = &prox_port_cfg[if_port]; + if (max_frame_size < port->mtu + PROX_RTE_ETHER_HDR_LEN + PROX_RTE_ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE) + max_frame_size = port->mtu + PROX_RTE_ETHER_HDR_LEN + PROX_RTE_ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE; + if (min_buffer_size < port->min_rx_bufsize) + min_buffer_size = port->min_rx_bufsize; + + // Check whether we receive from i40e. This driver have extra mbuf size requirements + if (strcmp(port->short_name, "i40e") == 0) + i40e = 1; + } + if (i40e) { + // i40e supports a maximum of 5 descriptors chained + uint16_t required_mbuf_size = RTE_ALIGN(max_frame_size / 5, 128) + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM; + if (required_mbuf_size > targ->mbuf_size) { + targ->mbuf_size = required_mbuf_size; + plog_info("\t\tSetting mbuf_size to %u to support frame_size %u\n", targ->mbuf_size, max_frame_size); + } + } + if (min_buffer_size > targ->mbuf_size) { + plog_warn("Mbuf size might be too small. This might result in packet segmentation and memory leak\n"); + } + +} + static void setup_mempools_unique_per_socket(void) { uint32_t flags = 0; @@ -595,11 +780,7 @@ static void setup_mempools_unique_per_socket(void) uint8_t socket = rte_lcore_to_socket_id(lconf->id); PROX_ASSERT(socket < MAX_SOCKETS); - if (targ->mbuf_size_set_explicitely) - flags = MEMPOOL_F_NO_SPREAD; - if ((!targ->mbuf_size_set_explicitely) && (targ->task_init->mbuf_size != 0)) { - targ->mbuf_size = targ->task_init->mbuf_size; - } + set_mbuf_size(targ); if (targ->rx_port_queue[0].port != OUT_DISCARD) { struct prox_port_cfg* port_cfg = &prox_port_cfg[targ->rx_port_queue[0].port]; PROX_ASSERT(targ->nb_mbuf != 0); @@ -616,28 +797,26 @@ static void setup_mempools_unique_per_socket(void) PROX_PANIC(mbuf_size[socket] != targ->mbuf_size, "all mbuf_size must have the same size if using a unique mempool per socket\n"); } - if ((!targ->mbuf_size_set_explicitely) && (strcmp(port_cfg->short_name, "vmxnet3") == 0)) { - if (mbuf_size[socket] < MBUF_SIZE + RTE_PKTMBUF_HEADROOM) - mbuf_size[socket] = MBUF_SIZE + RTE_PKTMBUF_HEADROOM; - } } } for (int i = 0 ; i < MAX_SOCKETS; i++) { if (mbuf_count[i] != 0) { sprintf(name, "socket_%u_pool", i); - pool[i] = rte_mempool_create(name, - mbuf_count[i] - 1, mbuf_size[i], - nb_cache_mbuf[i], - sizeof(struct rte_pktmbuf_pool_private), - rte_pktmbuf_pool_init, NULL, - prox_pktmbuf_init, NULL, - i, flags); - PROX_PANIC(pool[i] == NULL, "\t\tError: cannot create mempool for socket %u\n", i); - plog_info("\t\tMempool %p size = %u * %u cache %u, socket %d\n", pool[i], - mbuf_count[i], mbuf_size[i], nb_cache_mbuf[i], i); - - if (prox_cfg.flags & DSF_SHUFFLE) { - shuffle_mempool(pool[i], mbuf_count[i]); + if ((pool[i] = rte_mempool_lookup(name)) == NULL) { + pool[i] = rte_mempool_create(name, + mbuf_count[i] - 1, mbuf_size[i], + nb_cache_mbuf[i], + sizeof(struct rte_pktmbuf_pool_private), + rte_pktmbuf_pool_init, NULL, + prox_pktmbuf_init, NULL, + i, flags); + PROX_PANIC(pool[i] == NULL, "\t\tError: cannot create mempool for socket %u\n", i); + plog_info("\tMempool %p size = %u * %u cache %u, socket %d\n", pool[i], + mbuf_count[i], mbuf_size[i], nb_cache_mbuf[i], i); + + if (prox_cfg.flags & DSF_SHUFFLE) { + shuffle_mempool(pool[i], mbuf_count[i]); + } } } } @@ -652,7 +831,7 @@ static void setup_mempools_unique_per_socket(void) targ->pool = pool[socket]; /* Set the number of mbuf to the number of the unique mempool, so that the used and free work */ targ->nb_mbuf = mbuf_count[socket]; - plog_info("\t\tMempool %p size = %u * %u cache %u, socket %d\n", targ->pool, + plog_info("\tMempool %p size = %u * %u cache %u, socket %d\n", targ->pool, targ->nb_mbuf, mbuf_size[socket], targ->nb_cache_mbuf, socket); } } @@ -668,33 +847,16 @@ static void setup_mempool_for_rx_task(struct lcore_cfg *lconf, struct task_args char memzone_name[64]; char name[64]; - /* mbuf size can be set - * - from config file (highest priority, overwriting any other config) - should only be used as workaround - * - through each 'mode', overwriting the default mbuf_size - * - defaulted to MBUF_SIZE i.e. 1518 Bytes - * Except is set expliciteky, ensure that size is big enough for vmxnet3 driver - */ - if (targ->mbuf_size_set_explicitely) { - flags = MEMPOOL_F_NO_SPREAD; - /* targ->mbuf_size already set */ - } - else if (targ->task_init->mbuf_size != 0) { - /* mbuf_size not set through config file but set through mode */ - targ->mbuf_size = targ->task_init->mbuf_size; - } - else if (strcmp(port_cfg->short_name, "vmxnet3") == 0) { - if (targ->mbuf_size < MBUF_SIZE + RTE_PKTMBUF_HEADROOM) - targ->mbuf_size = MBUF_SIZE + RTE_PKTMBUF_HEADROOM; - } + set_mbuf_size(targ); /* allocate memory pool for packets */ PROX_ASSERT(targ->nb_mbuf != 0); if (targ->pool_name[0] == '\0') { - sprintf(name, "core_%u_port_%u_pool", lconf->id, targ->id); + sprintf(name, "core_%u_task_%u_pool", lconf->id, targ->id); } - snprintf(memzone_name, sizeof(memzone_name)-1, "MP_%s", targ->pool_name); + snprintf(memzone_name, sizeof(memzone_name), "MP_%.*s", (int)(sizeof(memzone_name)-4), targ->pool_name); mz = rte_memzone_lookup(memzone_name); if (mz != NULL) { @@ -724,7 +886,7 @@ static void setup_mempool_for_rx_task(struct lcore_cfg *lconf, struct task_args receiving from if one core receives from multiple ports, all the ports use the same mempool */ if (targ->pool == NULL) { - plog_info("\t\tCreating mempool with name '%s'\n", name); + plog_info("\tCreating mempool with name '%s' on socket %d\n", name, socket); targ->pool = rte_mempool_create(name, targ->nb_mbuf - 1, targ->mbuf_size, targ->nb_cache_mbuf, @@ -735,9 +897,9 @@ static void setup_mempool_for_rx_task(struct lcore_cfg *lconf, struct task_args } PROX_PANIC(targ->pool == NULL, - "\t\tError: cannot create mempool for core %u port %u: %s\n", lconf->id, targ->id, rte_strerror(rte_errno)); + "\tError: cannot create mempool for core %u port %u: %s\n", lconf->id, targ->id, rte_strerror(rte_errno)); - plog_info("\t\tMempool %p size = %u * %u cache %u, socket %d\n", targ->pool, + plog_info("\tMempool %p size = %u * %u cache %u, socket %d\n", targ->pool, targ->nb_mbuf, targ->mbuf_size, targ->nb_cache_mbuf, socket); if (prox_cfg.flags & DSF_SHUFFLE) { shuffle_mempool(targ->pool, targ->nb_mbuf); @@ -829,10 +991,10 @@ static void setup_all_task_structs(void) while(prox_core_next(&lcore_id, 1) == 0) { lconf = &lcore_cfg[lcore_id]; - plog_info("\tInitializing struct for core %d with %d task\n", lcore_id, lconf->n_tasks_all); + plog_info("\t*** Initializing core %d (%d task) ***\n", lcore_id, lconf->n_tasks_all); for (uint8_t task_id = 0; task_id < lconf->n_tasks_all; ++task_id) { if (!task_is_master(&lconf->targs[task_id])) { - plog_info("\tInitializing struct for core %d task %d\n", lcore_id, task_id); + plog_info("\t\tInitializing struct for core %d task %d\n", lcore_id, task_id); lconf->targs[task_id].tmaster = tmaster; lconf->tasks_all[task_id] = init_task_struct(&lconf->targs[task_id]); } @@ -888,14 +1050,13 @@ static void init_lcores(void) plog_info("=== Initializing rings on cores ===\n"); init_rings(); + configure_multi_segments(); + configure_tx_queue_flags(); + plog_info("=== Checking configuration consistency ===\n"); check_cfg_consistent(); plog_all_rings(); - - setup_all_task_structs_early_init(); - plog_info("=== Initializing tasks ===\n"); - setup_all_task_structs(); } static int setup_prox(int argc, char **argv) @@ -923,6 +1084,10 @@ static int setup_prox(int argc, char **argv) plog_info("=== Initializing ports ===\n"); init_port_all(); + setup_all_task_structs_early_init(); + plog_info("=== Initializing tasks ===\n"); + setup_all_task_structs(); + if (prox_cfg.logbuf_size) { prox_cfg.logbuf = prox_zmalloc(prox_cfg.logbuf_size, rte_socket_id()); PROX_PANIC(prox_cfg.logbuf == NULL, "Failed to allocate memory for logbuf with size = %d\n", prox_cfg.logbuf_size); @@ -1009,6 +1174,40 @@ static void sigterm_handler(int signum) quit(); } +static void set_term_env(void) +{ + static const char var[] = "TERM"; + static char str[] = "TERM=putty"; + char *old_value, *new_value; + int max_ver = 0, min_ver = 0, n; + + old_value = getenv(var); + + const char *ncurses_version = curses_version(); + n = sscanf(ncurses_version, "ncurses %d.%d", &max_ver, &min_ver); + if (n != 2) { + plog_info("\tUnable to extract ncurses version from %s. TERM left unchanged to %s\n", ncurses_version, old_value); + return; + } else { + plog_info("\tncurses version = %d.%d (%s)\n", max_ver, min_ver, ncurses_version); + } + + if ((old_value) && ((max_ver > 6) || ((max_ver == 6) && (min_ver >= 1))) && (strcmp(old_value, "xterm") == 0)) { + // On recent OSes such as RHEL 8.0, ncurses(6.1) introduced support + // for ECMA-48 repeat character control. + // Some terminal emulators use TERM=xterm but do not support this feature. + // In this case, printing repeating character such as "22000000 Hz" might + // display as 220 Hz. + // Other emulattors, such as tmux, use TERM=screen, and do not exhibit the issue. + plog_info("\tChanged TERM from %s ", old_value); + putenv(str); + new_value = getenv(var); + plog_info("to %s\n", new_value); + } else { + plog_info("\tTERM left unchanged to %s\n", old_value); + } +} + int main(int argc, char **argv) { /* set en_US locale to print big numbers with ',' */ @@ -1017,10 +1216,11 @@ int main(int argc, char **argv) if (prox_parse_args(argc, argv) != 0){ prox_usage(argv[0]); } - plog_init(prox_cfg.log_name, prox_cfg.log_name_pid); - plog_info("=== " PROGRAM_NAME " " VERSION_STR " ===\n"); + plog_info("=== " PROGRAM_NAME " %s ===\n", VERSION_STR()); plog_info("\tUsing DPDK %s\n", rte_version() + sizeof(RTE_VER_PREFIX)); + plog_info("\tgit version %s\n", git_version); + set_term_env(); read_rdt_info(); if (prox_cfg.flags & DSF_LIST_TASK_MODES) { @@ -1087,5 +1287,6 @@ int main(int argc, char **argv) if (setup_prox(argc, argv) != 0) return EXIT_FAILURE; run(prox_cfg.flags); + return EXIT_SUCCESS; }