Skip to content

Commit 506fab4

Browse files
rjarrychristophefontaine
authored andcommitted
port: handle RTE_ETH_EVENT_INTR_RESET events
Register a callback for RTE_ETH_EVENT_INTR_RESET which is raised by some DPDK drivers when the hardware requires a reset. This typically happens when the PF driver modifies VF settings from the host side, for example when changing a VF MAC address via ip link: ip link set $pf vf $vf_num mac $mac When the reset event is received, the port is fully reset and reconfigured via rte_eth_dev_reset() followed by rte_eth_dev_configure() and rte_eth_dev_start(). The MAC address is re-read from hardware to pick up any changes made by the PF. The DPDK callback may be invoked from internal threads and multiple reset events can occur before the main event loop processes them. To handle this, port IDs are queued in a mutex-protected vector and processed in batch when the libevent callback fires. Note that RTE_ETH_EVENT_INTR_RESET support varies by driver. The Intel iavf driver reports this event when the VF MAC is changed from the PF. The mlx5 driver does not report this event in the same scenario. Signed-off-by: Robin Jarry <rjarry@redhat.com> Reviewed-by: Christophe Fontaine <cfontain@redhat.com>
1 parent cdc4398 commit 506fab4

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

modules/infra/control/gr_port.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ GR_IFACE_INFO(GR_IFACE_TYPE_PORT, iface_info_port, {
2828

2929
uint16_t port_id;
3030
bool started;
31+
bool needs_reset;
3132
struct rte_mempool *pool;
3233
char *devargs;
3334
uint32_t pool_size;

modules/infra/control/port.c

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <rte_malloc.h>
2929

3030
#include <arpa/inet.h>
31+
#include <pthread.h>
3132
#include <stdio.h>
3233
#include <string.h>
3334

@@ -281,11 +282,17 @@ static int iface_port_reconfig(
281282
needs_configure = true;
282283
}
283284

284-
if (p->started && needs_configure) {
285+
if (p->started && (needs_configure || p->needs_reset)) {
285286
p->started = false;
286287
rte_rcu_qsbr_synchronize(gr_datapath_rcu(), RTE_QSBR_THRID_INVALID);
287-
if ((ret = rte_eth_dev_stop(p->port_id)) < 0)
288+
if (p->needs_reset) {
289+
p->needs_reset = false;
290+
needs_configure = true;
291+
if ((ret = rte_eth_dev_reset(p->port_id)) < 0)
292+
return errno_log(-ret, "rte_eth_dev_reset");
293+
} else if ((ret = rte_eth_dev_stop(p->port_id)) < 0) {
288294
return errno_log(-ret, "rte_eth_dev_stop");
295+
}
289296
}
290297

291298
if (needs_configure) {
@@ -668,6 +675,51 @@ static int lsc_port_cb(
668675
return 0;
669676
}
670677

678+
static struct event *reset_event;
679+
static gr_vec uint16_t *reset_ports;
680+
static pthread_mutex_t reset_ports_lock = PTHREAD_MUTEX_INITIALIZER;
681+
682+
static int intr_reset_cb(
683+
uint16_t port_id,
684+
enum rte_eth_event_type,
685+
void * /*cb_arg*/,
686+
void * /*ret_param*/
687+
) {
688+
// Multiple VFs may be reset before reset_event is fired in the main loop.
689+
// Queue the port IDs in a vector protected by a mutex so that they are all
690+
// processed in port_reset_cb().
691+
pthread_mutex_lock(&reset_ports_lock);
692+
gr_vec_add(reset_ports, port_id);
693+
pthread_mutex_unlock(&reset_ports_lock);
694+
// This callback may be executed from any dataplane or DPDK thread.
695+
// In order to serialize the reset of the port, propagate the callback
696+
// event to the event loop running in the main lcore.
697+
event_active(reset_event, 0, 0);
698+
return 0;
699+
}
700+
701+
static void port_reset_cb(evutil_socket_t, short, void * /*priv*/) {
702+
gr_vec uint16_t *port_ids;
703+
704+
// reset the port_id queue
705+
pthread_mutex_lock(&reset_ports_lock);
706+
port_ids = reset_ports;
707+
reset_ports = NULL;
708+
pthread_mutex_unlock(&reset_ports_lock);
709+
710+
gr_vec_foreach (uint16_t pid, port_ids) {
711+
struct iface *iface = (struct iface *)port_get_iface(pid);
712+
if (iface != NULL) {
713+
struct iface_info_port *port = iface_info_port(iface);
714+
struct gr_iface_info_port api = {.mac = {{0}}};
715+
LOG(INFO, "%s: port %u reset", iface->name, pid);
716+
port->needs_reset = true;
717+
iface_port_reconfig(iface, GR_PORT_SET_MAC, NULL, &api);
718+
}
719+
}
720+
gr_vec_free(port_ids);
721+
}
722+
671723
static void port_init(struct event_base *base) {
672724
link_event = event_new(base, -1, EV_PERSIST | EV_FINALIZE, link_event_cb, NULL);
673725
if (link_event == NULL)
@@ -678,12 +730,22 @@ static void port_init(struct event_base *base) {
678730
if (event_add(link_event, &tv) < 0)
679731
ABORT("event_add() failed");
680732
rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_LSC, lsc_port_cb, NULL);
733+
734+
// register an interrupt callback for port hardware reset events
735+
reset_event = event_new(base, -1, EV_PERSIST | EV_FINALIZE, port_reset_cb, NULL);
736+
if (reset_event == NULL)
737+
ABORT("event_new() failed");
738+
rte_eth_dev_callback_register(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_RESET, intr_reset_cb, NULL);
681739
}
682740

683741
static void port_fini(struct event_base *) {
684742
rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_LSC, lsc_port_cb, NULL);
685743
event_free(link_event);
686744
link_event = NULL;
745+
rte_eth_dev_callback_unregister(RTE_ETH_ALL, RTE_ETH_EVENT_INTR_RESET, intr_reset_cb, NULL);
746+
event_free(reset_event);
747+
reset_event = NULL;
748+
gr_vec_free(reset_ports);
687749
}
688750

689751
static struct iface_type iface_type_port = {

0 commit comments

Comments
 (0)