blob: 5c6843019233403de5972e792d664bc65f4e0b84 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 "nic.h"
/**
* Default receive queue settings.
*/
static const struct rte_eth_conf rx_conf_default = {
.rxmode = {
.mq_mode = ETH_MQ_RX_RSS,
.max_rx_pkt_len = ETHER_MAX_LEN,
.enable_scatter = 0,
.enable_lro = 0
},
.txmode = {
.mq_mode = ETH_MQ_TX_NONE,
},
.rx_adv_conf = {
.rss_conf = {
.rss_hf = ETH_RSS_IP | ETH_RSS_UDP | ETH_RSS_TCP | ETH_RSS_SCTP,
}
},
};
/**
* Default transmit queue settings.
*/
static const struct rte_eth_txconf tx_conf_default = {
.tx_thresh = {
.pthresh = 0,
.hthresh = 0,
.wthresh = 0
},
.tx_rs_thresh = 0,
.tx_free_thresh = 0,
.txq_flags = 0,
.tx_deferred_start = 0
};
/*
* Initialize a NIC port.
*/
static int init_port(
const uint8_t port_id,
struct rte_mempool* mem_pool,
const uint16_t nb_rx_queue,
const uint16_t nb_rx_desc)
{
struct rte_eth_conf rx_conf = rx_conf_default;
struct rte_eth_txconf tx_conf = tx_conf_default;
int retval;
uint16_t q;
int retry = 5;
const uint16_t tx_queues = 1;
int socket;
struct rte_eth_dev_info dev_info;
if (port_id >= rte_eth_dev_count()) {
rte_exit(EXIT_FAILURE, "Port does not exist; port=%u \n", port_id);
return -1;
}
// check that the number of RX queues does not exceed what is supported by the device
rte_eth_dev_info_get(port_id, &dev_info);
if (nb_rx_queue > dev_info.max_rx_queues) {
rte_exit(EXIT_FAILURE, "Too many RX queues for device; port=%u, rx_queues=%u, max_queues=%u \n",
port_id, nb_rx_queue, dev_info.max_rx_queues);
return -EINVAL;
}
// check that the number of TX queues does not exceed what is supported by the device
if (tx_queues > dev_info.max_tx_queues) {
rte_exit(EXIT_FAILURE, "Too many TX queues for device; port=%u, tx_queues=%u, max_queues=%u \n",
port_id, tx_queues, dev_info.max_tx_queues);
return -EINVAL;
}
retval = rte_eth_dev_configure(port_id, nb_rx_queue, tx_queues, &rx_conf);
if (retval != 0) {
rte_exit(EXIT_FAILURE, "Cannot configure device; port=%u, err=%s \n", port_id, strerror(-retval));
return retval;
}
// create the receive queues
socket = rte_eth_dev_socket_id(port_id);
for (q = 0; q < nb_rx_queue; q++) {
retval = rte_eth_rx_queue_setup(port_id, q, nb_rx_desc, socket, NULL, mem_pool);
if (retval != 0) {
rte_exit(EXIT_FAILURE, "Cannot setup RX queue; port=%u, err=%s \n", port_id, strerror(-retval));
return retval;
}
}
// create the transmit queues - at least one TX queue must be setup even though we don't use it
for (q = 0; q < tx_queues; q++) {
retval = rte_eth_tx_queue_setup(port_id, q, TX_QUEUE_SIZE, socket, &tx_conf);
if (retval != 0) {
rte_exit(EXIT_FAILURE, "Cannot setup TX queue; port=%u, err=%s \n", port_id, strerror(-retval));
return retval;
}
}
// start the receive and transmit units on the device
retval = rte_eth_dev_start(port_id);
if (retval < 0) {
rte_exit(EXIT_FAILURE, "Cannot start device; port=%u, err=%s \n", port_id, strerror(-retval));
return retval;
}
// retrieve information about the device
struct rte_eth_link link;
do {
rte_eth_link_get_nowait(port_id, &link);
} while (retry-- > 0 && !link.link_status && !sleep(1));
// if still no link information, must be down
if (!link.link_status) {
rte_exit(EXIT_FAILURE, "Link down; port=%u \n", port_id);
return 0;
}
// enable promisc mode
rte_eth_promiscuous_enable(port_id);
// print diagnostics
struct ether_addr addr;
rte_eth_macaddr_get(port_id, &addr);
LOG_INFO(USER1, "Device setup successfully; port=%u, mac=%02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 " %02" PRIx8 "\n",
(unsigned int) port_id,
addr.addr_bytes[0], addr.addr_bytes[1],
addr.addr_bytes[2], addr.addr_bytes[3],
addr.addr_bytes[4], addr.addr_bytes[5]);
return 0;
}
/*
* Preparation for receiving and processing packets.
*/
int init_receive(
const uint8_t enabled_port_mask,
const uint16_t nb_rx_queue,
const uint16_t nb_rx_desc)
{
unsigned int nb_ports_available;
unsigned int nb_ports;
unsigned int port_id;
unsigned int size;
nb_ports_available = nb_ports = rte_eth_dev_count();
// create memory pool
size = NUM_MBUFS * nb_ports;
struct rte_mempool* mem_pool = rte_pktmbuf_pool_create("mbuf-pool", size, MBUF_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
if (mem_pool == NULL) {
rte_exit(EXIT_FAILURE, "Unable to create memory pool; n=%u, cache_size=%u, data_room_size=%u, socket=%u \n",
size, MBUF_CACHE_SIZE, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
}
// initialize each specified ethernet ports
for (port_id = 0; port_id < nb_ports; port_id++) {
// skip over ports that are not enabled
if ((enabled_port_mask & (1 << port_id)) == 0) {
LOG_INFO(USER1, "Skipping over disabled port '%d'\n", port_id);
nb_ports_available--;
continue;
}
// initialize the port - creates one receive queue for each worker
LOG_INFO(USER1, "Initializing port %u\n", (unsigned)port_id);
if (init_port(port_id, mem_pool, nb_rx_queue, nb_rx_desc) != 0) {
rte_exit(EXIT_FAILURE, "Cannot initialize port %" PRIu8 "\n", port_id);
}
}
// ensure that we were able to initialize enough ports
if (nb_ports_available < 1) {
rte_exit(EXIT_FAILURE, "Error: No available enabled ports. Portmask set?\n");
}
return 0;
}
/*
* Preparation for transmitting packets.
*/
int init_transmit(
struct rte_ring **tx_rings,
const unsigned int count,
const unsigned int size)
{
unsigned int i;
char buf[32];
for(i = 0; i < count; i++) {
sprintf(buf, "tx-ring-%d", i);
tx_rings[i] = rte_ring_create(buf, size, rte_socket_id(), RING_F_SP_ENQ);
if(NULL == tx_rings[i]) {
rte_exit(EXIT_FAILURE, "Unable to create transmit ring: %s \n", rte_strerror(rte_errno));
}
}
return 0;
}