Skip to content

Commit

Permalink
DPDK: Add Ethernet HW Flow Control feature
Browse files Browse the repository at this point in the history
Add an option to enable/disable sending and respecting PAUSE frames as defined in
802.3x and 802.3z specifications. We will configure the Link level PAUSEs
(as opposed to PFC).

In simple words Ethernel Flow Control relies on sending/receiving PAUSE (XOFF) MAC frames that
indicate the sender that receiver's buffer is almost full. The idea is to avoid receive buffer overflow. When
receiver's buffer is being freed it will send XON frame to indicate to the sender that it may
transmit again.

   - Added DPDK-specific command option to toggle the feature.
   - Sending PAUSEs is enabled by default.

Signed-off-by: Vlad Zolotarov <vladz@cloudius-systems.com>
  • Loading branch information
Vlad Zolotarov authored and avikivity committed Apr 16, 2015
1 parent 4144711 commit 934c6ac
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 5 deletions.
48 changes: 45 additions & 3 deletions net/dpdk.cc
Expand Up @@ -201,6 +201,7 @@ class dpdk_device : public device {
uint8_t _queues_ready = 0;
unsigned _home_cpu;
bool _use_lro;
bool _enable_fc;
std::vector<uint8_t> _redir_table;
#ifdef RTE_VERSION_1_7
struct rte_eth_rxconf _rx_conf_default = {};
Expand Down Expand Up @@ -251,12 +252,19 @@ class dpdk_device : public device {
*/
void check_port_link_status();

/**
* Configures the HW Flow Control
*/
void set_hw_flow_control();

public:
dpdk_device(uint8_t port_idx, uint16_t num_queues, bool use_lro)
dpdk_device(uint8_t port_idx, uint16_t num_queues, bool use_lro,
bool enable_fc)
: _port_idx(port_idx)
, _num_queues(num_queues)
, _home_cpu(engine().cpu_id())
, _use_lro(use_lro)
, _enable_fc(enable_fc)
, _stats_plugin_name("network")
, _stats_plugin_inst(std::string("port") + std::to_string(_port_idx))
{
Expand Down Expand Up @@ -1383,8 +1391,35 @@ int dpdk_device::init_port_start()
return 0;
}

void dpdk_device::set_hw_flow_control()
{
// Read the port's current/default flow control settings
struct rte_eth_fc_conf fc_conf;
auto ret = rte_eth_dev_flow_ctrl_get(_port_idx, &fc_conf);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "Port %u: failed to get hardware flow control settings: (error %d)\n", _port_idx, ret);
}

if (_enable_fc) {
fc_conf.mode = RTE_FC_FULL;
} else {
fc_conf.mode = RTE_FC_NONE;
}

printf("Port %u: %s HW FC\n", _port_idx,
(_enable_fc ? "Enabling" : "Disabling"));

ret = rte_eth_dev_flow_ctrl_set(_port_idx, &fc_conf);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "Port %u: failed to set hardware flow control (error %d)\n", _port_idx, ret);
}
}

void dpdk_device::init_port_fini()
{
// Changing FC requires HW reset, so set it before the port is initialized.
set_hw_flow_control();

if (rte_eth_dev_start(_port_idx) < 0) {
rte_exit(EXIT_FAILURE, "Cannot start port %d\n", _port_idx);
}
Expand Down Expand Up @@ -1902,7 +1937,8 @@ std::unique_ptr<qp> dpdk_device::init_local_queue(boost::program_options::variab
std::unique_ptr<net::device> create_dpdk_net_device(
uint8_t port_idx,
uint8_t num_queues,
bool use_lro)
bool use_lro,
bool enable_fc)
{
static bool called = false;

Expand All @@ -1918,14 +1954,20 @@ std::unique_ptr<net::device> create_dpdk_net_device(
printf("ports number: %d\n", rte_eth_dev_count());
}

return std::make_unique<dpdk::dpdk_device>(port_idx, num_queues, use_lro);
return std::make_unique<dpdk::dpdk_device>(port_idx, num_queues, use_lro,
enable_fc);
}

boost::program_options::options_description
get_dpdk_net_options_description()
{
boost::program_options::options_description opts(
"DPDK net options");

opts.add_options()
("hw-fc",
boost::program_options::value<std::string>()->default_value("on"),
"Enable HW Flow Control (on / off)");
#if 0
opts.add_options()
("csum-offload",
Expand Down
3 changes: 2 additions & 1 deletion net/dpdk.hh
Expand Up @@ -31,7 +31,8 @@
std::unique_ptr<net::device> create_dpdk_net_device(
uint8_t port_idx = 0,
uint8_t num_queues = 1,
bool use_lro = true);
bool use_lro = true,
bool enable_fc = true);

boost::program_options::options_description get_dpdk_net_options_description();

Expand Down
3 changes: 2 additions & 1 deletion net/native-stack.cc
Expand Up @@ -86,7 +86,8 @@ void create_native_net_device(boost::program_options::variables_map opts) {
// Hardcoded port index 0.
// TODO: Inherit it from the opts
dev = create_dpdk_net_device(0, smp::count,
!(opts.count("lro") && opts["lro"].as<std::string>() == "off"));
!(opts.count("lro") && opts["lro"].as<std::string>() == "off"),
!(opts.count("hw-fc") && opts["hw-fc"].as<std::string>() == "off"));
} else
#endif
dev = create_virtio_net_device(opts);
Expand Down

0 comments on commit 934c6ac

Please sign in to comment.