X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=VNFs%2FDPPD-PROX%2Fmain.c;h=ed578c8536fdad6fe36f8d9c619e12220cf3f720;hb=4805ad5dc114b24724b754443c2fc1e6957f6e3a;hp=59a169d8c41d4a8f56dc7171f604e79d1ae4e296;hpb=0250340696153af1c8536f3a38eb99e1b67a2ea2;p=samplevnf.git diff --git a/VNFs/DPPD-PROX/main.c b/VNFs/DPPD-PROX/main.c index 59a169d8..ed578c85 100644 --- a/VNFs/DPPD-PROX/main.c +++ b/VNFs/DPPD-PROX/main.c @@ -127,11 +127,33 @@ 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; while (core_targ_next(&lconf, &targ, 0) == 0) { @@ -192,6 +214,7 @@ static void check_missing_rx(void) static void check_cfg_consistent(void) { + check_nb_mbuf(); check_missing_rx(); check_zero_rx(); check_mixed_normal_pipeline(); @@ -224,6 +247,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,39 +285,19 @@ 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 - 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, 0)) { +#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 all of the tasks up to the task - transmitting to the port use no_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 &= ~(DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM); } +#endif } } @@ -293,26 +311,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(port->rx_ring[0] != '\0') { port->n_rxq = 0; } - // Force multi segment support if mbuf size is not big enough. + // 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 + ETHER_HDR_LEN + 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_NOMULTSEGS; - plog_info("\t\tDisabling No MultSegs on port %u as %lu > %u\n", if_port, 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 = prox_port_cfg[if_port].n_rxq; + 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); } @@ -333,6 +351,62 @@ static void configure_if_queues(void) } } +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 DEV_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 |= DEV_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 |= DEV_TX_OFFLOAD_MULTI_SEGS; + } +#endif + } + } +} + static const char *gen_ring_name(void) { static char retval[] = "XX"; @@ -450,7 +524,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++; @@ -509,6 +583,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; @@ -561,7 +637,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); } } } @@ -571,13 +647,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); @@ -591,20 +668,16 @@ 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 - * - through each 'mode', overwriting the default mbuf_size - * - defaulted to MBUF_SIZE i.e. 1518 Bytes + * - defaulted to MBUF_SIZE. * Except if set explicitely, ensure that size is big enough for vmxnet3 driver */ - if (targ->mbuf_size_set_explicitely) + if (targ->mbuf_size) return; - 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; - } - + targ->mbuf_size = MBUF_SIZE; struct prox_port_cfg *port; - uint16_t max_frame_size = 0; + 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; @@ -614,22 +687,24 @@ static void set_mbuf_size(struct task_args *targ) port = &prox_port_cfg[if_port]; if (max_frame_size < port->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE) max_frame_size = port->mtu + ETHER_HDR_LEN + ETHER_CRC_LEN + 2 * PROX_VLAN_TAG_SIZE; + if (min_buffer_size < port->min_rx_bufsize) + min_buffer_size = port->min_rx_bufsize; - if (strcmp(port->short_name, "vmxnet3") == 0) { - if (targ->mbuf_size < MBUF_SIZE + RTE_PKTMBUF_HEADROOM) - targ->mbuf_size = MBUF_SIZE + RTE_PKTMBUF_HEADROOM; - if (targ->mbuf_size < max_frame_size) - targ->mbuf_size = max_frame_size + RTE_PKTMBUF_HEADROOM; - } + // Check whether we receive from i40e. This driver have extra mbuf size requirements + if (strcmp(port->short_name, "i40e") == 0) + i40e = 1; } - if (max_frame_size) { + 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 (mtu %u)\n", targ->mbuf_size, max_frame_size, port->mtu); + 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"); + } } @@ -918,14 +993,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) @@ -953,6 +1027,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);