[dpdk-dev,V12,3/3] app/testpmd: use uevent to monitor hotplug
Checks
Commit Message
use testpmd for example, to show app how to request and use
uevent monitoring to handle the hot removal event and the
hot insertion event.
Signed-off-by: Jeff Guo <jia.guo@intel.com>
---
v12->v11:
no change
---
app/test-pmd/testpmd.c | 168 +++++++++++++++++++++++++++++++++++++++++++++++++
app/test-pmd/testpmd.h | 9 +++
2 files changed, 177 insertions(+)
Comments
> +
> +static void
> +add_uevent_callback(void *arg)
> +{
> + char *dev_name = (char *)arg;
> +
> + rte_eal_alarm_cancel(add_uevent_callback, arg);
> +
> + if (!in_hotplug_list(dev_name))
> + return;
> +
> + RTE_LOG(ERR, EAL, "add device: %s\n", dev_name);
It's not an error, replace by printf?
> + attach_port(dev_name);
> +}
> +
> /* This function is used by the interrupt thread */
> static int
> eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
> @@ -1931,6 +2014,82 @@ eth_event_callback(portid_t port_id, enum
> rte_eth_event_type type, void *param,
> }
>
> static int
> +in_hotplug_list(const char *dev_name)
> +{
> + struct hotplug_request *hp_request = NULL;
> +
> + TAILQ_FOREACH(hp_request, &hp_list, next) {
> + if (!strcmp(hp_request->dev_name, dev_name))
> + break;
> + }
> +
> + if (hp_request)
> + return 1;
> +
Is it better to use TRUE and FALSE?
On 1/24/2018 11:21 PM, Wu, Jingjing wrote:
>> +
>> +static void
>> +add_uevent_callback(void *arg)
>> +{
>> + char *dev_name = (char *)arg;
>> +
>> + rte_eal_alarm_cancel(add_uevent_callback, arg);
>> +
>> + if (!in_hotplug_list(dev_name))
>> + return;
>> +
>> + RTE_LOG(ERR, EAL, "add device: %s\n", dev_name);
> It's not an error, replace by printf?
sure.
>> + attach_port(dev_name);
>> +}
>> +
>> /* This function is used by the interrupt thread */
>> static int
>> eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
>> @@ -1931,6 +2014,82 @@ eth_event_callback(portid_t port_id, enum
>> rte_eth_event_type type, void *param,
>> }
>>
>> static int
>> +in_hotplug_list(const char *dev_name)
>> +{
>> + struct hotplug_request *hp_request = NULL;
>> +
>> + TAILQ_FOREACH(hp_request, &hp_list, next) {
>> + if (!strcmp(hp_request->dev_name, dev_name))
>> + break;
>> + }
>> +
>> + if (hp_request)
>> + return 1;
>> +
> Is it better to use TRUE and FALSE?
ok,make sense.
@@ -373,6 +373,8 @@ uint8_t bitrate_enabled;
struct gro_status gro_ports[RTE_MAX_ETHPORTS];
uint8_t gro_flush_cycles = GRO_DEFAULT_FLUSH_CYCLES;
+static struct hotplug_request_list hp_list;
+
/* Forward function declarations */
static void map_port_queue_stats_mapping_registers(portid_t pi,
struct rte_port *port);
@@ -380,6 +382,13 @@ static void check_all_ports_link_status(uint32_t port_mask);
static int eth_event_callback(portid_t port_id,
enum rte_eth_event_type type,
void *param, void *ret_param);
+static int eth_uevent_callback(char *device_name, enum rte_dev_event_type type,
+ void *param);
+static int eth_uevent_callback_register(portid_t port_id);
+static int in_hotplug_list(const char *dev_name);
+
+static int hotplug_list_add(const char *dev_name,
+ enum rte_dev_event_type event);
/*
* Check if all the ports are started.
@@ -1729,6 +1738,27 @@ reset_port(portid_t pid)
printf("Done\n");
}
+static int
+eth_uevent_callback_register(portid_t port_id)
+{
+ int diag;
+ char device_name[128];
+
+ snprintf(device_name, sizeof(device_name),
+ "%s", rte_eth_devices[port_id].device->name);
+
+ /* register the uevent callback */
+
+ diag = rte_dev_callback_register(device_name,
+ eth_uevent_callback, (void *)(intptr_t)port_id);
+ if (diag) {
+ printf("Failed to setup uevent callback\n");
+ return -1;
+ }
+
+ return 0;
+}
+
void
attach_port(char *identifier)
{
@@ -1745,6 +1775,8 @@ attach_port(char *identifier)
if (rte_eth_dev_attach(identifier, &pi))
return;
+ eth_uevent_callback_register(pi);
+
socket_id = (unsigned)rte_eth_dev_socket_id(pi);
/* if socket_id is invalid, set to 0 */
if (check_socket_id(socket_id) < 0)
@@ -1756,6 +1788,8 @@ attach_port(char *identifier)
ports[pi].port_status = RTE_PORT_STOPPED;
+ hotplug_list_add(identifier, RTE_DEV_EVENT_REMOVE);
+
printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);
printf("Done\n");
}
@@ -1782,6 +1816,9 @@ detach_port(portid_t port_id)
nb_ports = rte_eth_dev_count();
+ hotplug_list_add(rte_eth_devices[port_id].device->name,
+ RTE_DEV_EVENT_ADD);
+
printf("Port '%s' is detached. Now total ports is %d\n",
name, nb_ports);
printf("Done\n");
@@ -1805,6 +1842,9 @@ pmd_test_exit(void)
close_port(pt_id);
}
}
+
+ rte_dev_event_monitor_stop();
+
printf("\nBye...\n");
}
@@ -1889,6 +1929,49 @@ rmv_event_callback(void *arg)
dev->device->name);
}
+static void
+rmv_uevent_callback(void *arg)
+{
+ char name[RTE_ETH_NAME_MAX_LEN];
+ uint8_t port_id = (intptr_t)arg;
+
+ rte_eal_alarm_cancel(rmv_uevent_callback, arg);
+
+ RTE_ETH_VALID_PORTID_OR_RET(port_id);
+ printf("removing port id:%u\n", port_id);
+
+ if (!in_hotplug_list(rte_eth_devices[port_id].device->name))
+ return;
+
+ stop_packet_forwarding();
+
+ stop_port(port_id);
+ close_port(port_id);
+ if (rte_eth_dev_detach(port_id, name)) {
+ RTE_LOG(ERR, USER1, "Failed to detach port '%s'\n", name);
+ return;
+ }
+
+ nb_ports = rte_eth_dev_count();
+
+ printf("Port '%s' is detached. Now total ports is %d\n",
+ name, nb_ports);
+}
+
+static void
+add_uevent_callback(void *arg)
+{
+ char *dev_name = (char *)arg;
+
+ rte_eal_alarm_cancel(add_uevent_callback, arg);
+
+ if (!in_hotplug_list(dev_name))
+ return;
+
+ RTE_LOG(ERR, EAL, "add device: %s\n", dev_name);
+ attach_port(dev_name);
+}
+
/* This function is used by the interrupt thread */
static int
eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
@@ -1931,6 +2014,82 @@ eth_event_callback(portid_t port_id, enum rte_eth_event_type type, void *param,
}
static int
+in_hotplug_list(const char *dev_name)
+{
+ struct hotplug_request *hp_request = NULL;
+
+ TAILQ_FOREACH(hp_request, &hp_list, next) {
+ if (!strcmp(hp_request->dev_name, dev_name))
+ break;
+ }
+
+ if (hp_request)
+ return 1;
+
+ return 0;
+}
+
+static int
+hotplug_list_add(const char *dev_name, enum rte_dev_event_type event)
+{
+ struct hotplug_request *hp_request;
+
+ hp_request = rte_zmalloc("hoplug request",
+ sizeof(*hp_request), 0);
+ if (hp_request == NULL) {
+ fprintf(stderr, "%s can not alloc memory\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ hp_request->dev_name = dev_name;
+ hp_request->event = event;
+
+ TAILQ_INSERT_TAIL(&hp_list, hp_request, next);
+
+ return 0;
+}
+
+/* This function is used by the interrupt thread */
+static int
+eth_uevent_callback(char *device_name, enum rte_dev_event_type type, void *arg)
+{
+ static const char * const event_desc[] = {
+ [RTE_DEV_EVENT_UNKNOWN] = "Unknown",
+ [RTE_DEV_EVENT_ADD] = "add",
+ [RTE_DEV_EVENT_REMOVE] = "remove",
+ };
+
+ if (type >= RTE_DEV_EVENT_MAX) {
+ fprintf(stderr, "%s called upon invalid event %d\n",
+ __func__, type);
+ fflush(stderr);
+ } else if (event_print_mask & (UINT32_C(1) << type)) {
+ printf("%s event\n",
+ event_desc[type]);
+ fflush(stdout);
+ }
+
+ switch (type) {
+ case RTE_DEV_EVENT_REMOVE:
+ if (rte_eal_alarm_set(100000,
+ rmv_uevent_callback, arg))
+ fprintf(stderr, "Could not set up deferred "
+ "device removal\n");
+ break;
+ case RTE_DEV_EVENT_ADD:
+ if (rte_eal_alarm_set(500000,
+ add_uevent_callback, (void *)device_name))
+ fprintf(stderr, "Could not set up deferred "
+ "device add\n");
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
set_tx_queue_stats_mapping_registers(portid_t port_id, struct rte_port *port)
{
uint16_t i;
@@ -2415,6 +2574,15 @@ main(int argc, char** argv)
nb_rxq, nb_txq);
init_config();
+
+ /* enable hot plug monitoring */
+ TAILQ_INIT(&hp_list);
+ rte_dev_event_monitor_start();
+ RTE_ETH_FOREACH_DEV(port_id) {
+ hotplug_list_add(rte_eth_devices[port_id].device->name,
+ RTE_DEV_EVENT_REMOVE);
+ eth_uevent_callback_register(port_id);
+ }
if (start_port(RTE_PORT_ALL) != 0)
rte_exit(EXIT_FAILURE, "Start ports failed\n");
@@ -63,6 +63,15 @@ typedef uint16_t streamid_t;
#define TM_MODE 0
#endif
+struct hotplug_request {
+ TAILQ_ENTRY(hotplug_request) next; /**< Callbacks list */
+ const char *dev_name; /* request device name */
+ enum rte_dev_event_type event; /**< device event type */
+};
+
+/** @internal Structure to keep track of registered callbacks */
+TAILQ_HEAD(hotplug_request_list, hotplug_request);
+
enum {
PORT_TOPOLOGY_PAIRED,
PORT_TOPOLOGY_CHAINED,