DPDK patches and discussions
 help / color / mirror / Atom feed
From: "Guo, Jia" <jia.guo@intel.com>
To: Matan Azrad <matan@mellanox.com>,
	"stephen@networkplumber.org" <stephen@networkplumber.org>,
	"bruce.richardson@intel.com" <bruce.richardson@intel.com>,
	"ferruh.yigit@intel.com" <ferruh.yigit@intel.com>,
	"konstantin.ananyev@intel.com" <konstantin.ananyev@intel.com>,
	"gaetan.rivet@6wind.com" <gaetan.rivet@6wind.com>,
	"jingjing.wu@intel.com" <jingjing.wu@intel.com>,
	Thomas Monjalon <thomas@monjalon.net>,
	Mordechay Haimovsky <motih@mellanox.com>,
	"harry.van.haaren@intel.com" <harry.van.haaren@intel.com>,
	"jianfeng.tan@intel.com" <jianfeng.tan@intel.com>
Cc: "jblunck@infradead.org" <jblunck@infradead.org>,
	"shreyansh.jain@nxp.com" <shreyansh.jain@nxp.com>,
	"dev@dpdk.org" <dev@dpdk.org>,
	"helin.zhang@intel.com" <helin.zhang@intel.com>
Subject: Re: [dpdk-dev] [PATCH V19 4/4] app/testpmd: use auto handle for hotplug
Date: Fri, 13 Apr 2018 18:48:26 +0800	[thread overview]
Message-ID: <42450faf-7969-9238-823b-26fa144325ac@intel.com> (raw)
In-Reply-To: <AM4PR0501MB265767EAAEB77AF7F0563812D2BC0@AM4PR0501MB2657.eurprd05.prod.outlook.com>

hi matan


On 4/12/2018 1:31 PM, Matan Azrad wrote:
> Hi All
>
> From: Jeff Guo, Friday, April 6, 2018 1:57 PM
>> Use testpmd for example, to show how an application smoothly handle
>> failure when device be hot removal, and show how to auto bind kernal driver
>> to preparing attach device when device being hot insertion.
> I saw the kmod of old devices were saved by name and the app hope that new device name will be as previous saved name.
> How can the application know which driver should be bind for any new device?
about which driver should be bind, that is assume that the app record 
the previous saved driver type,  if the device name match the name list 
,just auto bind the corresponding saved driver,
that is aim to application could bind driver at run time, we want to let 
application not detect the hotplug behaviors and running smoothly, that 
will benefit for further failsafe integrate and
live migration.
> Moreover, I think that the application should not deal with driver binding\remap and all this should be managed by the relevant PMDs -
> Looks like the bind mechanism should be managed directly by the PMDs and not annoying application to deal with it.
>
> Am I missing something?
  partial agree, binding/remap could be managed by PMD, or more by 
hotplug framework. but i don't found the problem to exposure a api to 
binding according app's policy. because, when
device hot insertion, the PMDs default to bind a kernel driver, then 
before running testpmd , we bind specific driver by "dpdk-devbind.py" to 
override the driver, then run app. that override is
also the user behavior but not PMDs, so i think the different just at 
run time or setup time. i don't know if i convinced you here.
>> Signed-off-by: Jeff Guo <jia.guo@intel.com>
>> ---
>> v19->v18:
>> clean code
>> ---
>>   app/test-pmd/testpmd.c | 199
>> +++++++++++++++++++++++++++++++++++++++++++------
>>   app/test-pmd/testpmd.h |   9 +++
>>   2 files changed, 184 insertions(+), 24 deletions(-)
>>
>> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index
>> d2c122a..d7fa913 100644
>> --- a/app/test-pmd/testpmd.c
>> +++ b/app/test-pmd/testpmd.c
>> @@ -285,6 +285,8 @@ uint8_t lsc_interrupt = 1; /* enabled by default */
>>    */
>>   uint8_t rmv_interrupt = 1; /* enabled by default */
>>
>> +#define HOT_PLUG_FOR_ALL_DEVICE -1
>> +#define ALL_CALLBACK -1
>>   uint8_t hot_plug = 0; /**< hotplug disabled by default. */
>>
>>   /*
>> @@ -387,6 +389,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);
>> @@ -397,9 +401,13 @@ static int eth_event_callback(portid_t port_id,  static
>> void eth_dev_event_callback(char *device_name,
>>   				enum rte_dev_event_type type,
>>   				void *param);
>> -static int eth_dev_event_callback_register(void);
>> -static int eth_dev_event_callback_unregister(void);
>> +static int eth_dev_event_callback_register(portid_t port_id); static
>> +int eth_dev_event_callback_unregister(portid_t port_id);
>> +
>> +static bool in_hotplug_list(const char *dev_name);
>>
>> +static int hotplug_list_add(struct rte_device *device,
>> +				enum rte_kernel_driver device_kdrv);
>>
>>   /*
>>    * Check if all the ports are started.
>> @@ -1120,11 +1128,17 @@ run_pkt_fwd_on_lcore(struct fwd_lcore *fc,
>> packet_fwd_t pkt_fwd)
>>   	uint64_t tics_datum;
>>   	uint64_t tics_current;
>>   	uint8_t idx_port, cnt_ports;
>> +	int ret;
>>
>>   	cnt_ports = rte_eth_dev_count();
>>   	tics_datum = rte_rdtsc();
>>   	tics_per_1sec = rte_get_timer_hz();
>>   #endif
>> +	if (hot_plug) {
>> +		ret = rte_dev_handle_hot_unplug();
>> +		if (ret)
>> +			printf("The device is being hot unplug!\n");
>> +	}
>>   	fsm = &fwd_streams[fc->stream_idx];
>>   	nb_fs = fc->stream_nb;
>>   	do {
>> @@ -1863,15 +1877,24 @@ reset_port(portid_t pid)  }
>>
>>   static int
>> -eth_dev_event_callback_register(void)
>> +eth_dev_event_callback_register(portid_t port_id)
>>   {
>>   	int ret;
>> +	char *device_name;
>>
>> +	/* if port id equal -1, unregister event callbacks for all device. */
> unregister => register
> And I think that HOT_PLUG_FOR_ALL_DEVICE is descriptive enough.
>
ok.
>> +	if (port_id == (portid_t)HOT_PLUG_FOR_ALL_DEVICE) {
>> +		device_name = NULL;
>> +	} else {
>> +		device_name = strdup(rte_eth_devices[port_id].device-
>>> name);
>> +		if (!device_name)
>> +			return -1;
>> +	}
>>   	/* register the device event callback */
>> -	ret = rte_dev_event_callback_register(NULL,
>> -		eth_dev_event_callback, NULL);
>> +	ret = rte_dev_event_callback_register(device_name,
>> +		eth_dev_event_callback, (void *)(intptr_t)port_id);
>>   	if (ret) {
>> -		printf("Failed to register device event callback\n");
>> +		printf("Failed to register device event callback.\n");
>>   		return -1;
>>   	}
> You missed device_name freeing.
got it.
>> @@ -1880,15 +1903,25 @@ eth_dev_event_callback_register(void)
>>
>>
>>   static int
>> -eth_dev_event_callback_unregister(void)
>> +eth_dev_event_callback_unregister(portid_t port_id)
>>   {
>>   	int ret;
>> +	char *device_name;
>> +
>> +	/* if port id equal -1, unregister all device event callbacks */
>> +	if (port_id == (portid_t)HOT_PLUG_FOR_ALL_DEVICE) {
>> +		device_name = NULL;
>> +	} else {
>> +		device_name = strdup(rte_eth_devices[port_id].device-
>>> name);
>> +		if (!device_name)
>> +			return -1;
>> +	}
>>
>>   	/* unregister the device event callback */
>> -	ret = rte_dev_event_callback_unregister(NULL,
>> -		eth_dev_event_callback, NULL);
>> -	if (ret < 0) {
>> -		printf("Failed to unregister device event callback\n");
>> +	ret = rte_dev_event_callback_unregister(device_name,
>> +		eth_dev_event_callback, (void *)(intptr_t)port_id);
> Also here.
>
>> +	if (ret) {
>> +		printf("Failed to unregister device event callback.\n");
>>   		return -1;
>>   	}
>>
>> @@ -1911,6 +1944,8 @@ attach_port(char *identifier)
>>   	if (rte_eth_dev_attach(identifier, &pi))
>>   		return;
>>
>> +	eth_dev_event_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)
>> @@ -1922,6 +1957,12 @@ attach_port(char *identifier)
>>
>>   	ports[pi].port_status = RTE_PORT_STOPPED;
>>
>> +	if (hot_plug) {
>> +		hotplug_list_add(rte_eth_devices[pi].device,
>> +				 rte_eth_devices[pi].data->kdrv);
>> +		eth_dev_event_callback_register(pi);
>> +	}
>> +
>>   	printf("Port %d is attached. Now total ports is %d\n", pi, nb_ports);
>>   	printf("Done\n");
>>   }
>> @@ -1933,6 +1974,12 @@ detach_port(portid_t port_id)
>>
>>   	printf("Detaching a port...\n");
>>
>> +	if (hot_plug) {
>> +		hotplug_list_add(rte_eth_devices[port_id].device,
>> +				 rte_eth_devices[port_id].data->kdrv);
>> +		eth_dev_event_callback_register(port_id);
>> +	}
>> +
>>   	if (!port_is_closed(port_id)) {
>>   		printf("Please close port first\n");
>>   		return;
>> @@ -1979,7 +2026,7 @@ pmd_test_exit(void)
>>   			RTE_LOG(ERR, EAL,
>>   				"fail to stop device event monitor.");
>>
>> -		ret = eth_dev_event_callback_unregister();
>> +		ret = eth_dev_event_callback_unregister(ALL_CALLBACK);
>>   		if (ret)
>>   			RTE_LOG(ERR, EAL,
>>   				"fail to unregister all event callbacks."); @@ -
>> 2068,6 +2115,40 @@ rmv_event_callback(void *arg)
>>   			dev->device->name);
>>   }
>>
>> +static void
>> +rmv_dev_event_callback(void *arg)
>> +{
>> +	uint8_t port_id = (intptr_t)arg;
>> +
>> +	rte_eal_alarm_cancel(rmv_dev_event_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);
>> +	detach_port(port_id);
> Did you check the synchronization with the RMV event callback of ethdev?
i guess you mean the RMV event from which PMDs have implement this 
hotplug event. right?
>> +}
>> +
>> +static void
>> +add_dev_event_callback(void *arg)
>> +{
>> +	char *dev_name = (char *)arg;
>> +
>> +	rte_eal_alarm_cancel(add_dev_event_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, @@ -2114,31 +2195,96 @@ eth_event_callback(portid_t port_id,
>> enum rte_eth_event_type type, void *param,
>>   	return 0;
>>   }
>>
>> +static bool
>> +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 true;
>> +
>> +	return false;
>> +}
>> +
>> +static enum rte_kernel_driver
>> +get_hotplug_driver(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))
>> +			return hp_request->dev_kdrv;
>> +	}
>> +	return -1;
>> +}
>> +
>> +static int
>> +hotplug_list_add(struct rte_device *device, enum rte_kernel_driver
>> +device_kdrv) {
>> +	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 = device->name;
>> +	hp_request->dev_kdrv = device_kdrv;
>> +
>> +	TAILQ_INSERT_TAIL(&hp_list, hp_request, next);
>> +
>> +	return 0;
>> +}
>> +
>>   /* This function is used by the interrupt thread */  static void
>> eth_dev_event_callback(char *device_name, enum rte_dev_event_type
>> type,
>> -			     __rte_unused void *arg)
>> +				void *arg)
>>   {
>> +	static const char * const event_desc[] = {
>> +		[RTE_DEV_EVENT_ADD] = "add",
>> +		[RTE_DEV_EVENT_REMOVE] = "remove",
>> +	};
>> +	char *dev_name = malloc(strlen(device_name) + 1);
>> +
>> +	strcpy(dev_name, device_name);
>> +
>>   	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);
>>   	}
>>
> You need to use port_id_is_invalid() to check the port validity.
>   
ok
>>   	switch (type) {
>>   	case RTE_DEV_EVENT_REMOVE:
>> -		RTE_LOG(ERR, EAL, "The device: %s has been removed!\n",
>> -			device_name);
>> -		/* TODO: After finish failure handle, begin to stop
>> -		 * packet forward, stop port, close port, detach port.
>> -		 */
>> +		if (rte_eal_alarm_set(100000,
>> +			rmv_dev_event_callback, arg))
>> +			fprintf(stderr, "Could not set up deferred "
>> +				"device removal\n");
>>   		break;
>>   	case RTE_DEV_EVENT_ADD:
>> -		RTE_LOG(ERR, EAL, "The device: %s has been added!\n",
>> -			device_name);
>> -		/* TODO: After finish kernel driver binding,
>> -		 * begin to attach port.
>> +		/**
>> +		 * bind the driver to the device
>> +		 * before process of hot plug adding device
>>   		 */
>> +		rte_dev_bind_kernel_driver(dev_name,
>> +					   get_hotplug_driver(dev_name));
>> +		if (rte_eal_alarm_set(100000,
>> +			add_dev_event_callback, dev_name))
>> +			fprintf(stderr, "Could not set up deferred "
>> +				"device add\n");
>>   		break;
>>   	default:
>>   		break;
>> @@ -2638,8 +2784,13 @@ main(int argc, char** argv)
>>   			rte_errno = EINVAL;
>>   			return -1;
>>   		}
>> -		eth_dev_event_callback_register();
>> -
>> +		if (TAILQ_EMPTY(&hp_list))
>> +			TAILQ_INIT(&hp_list);
>> +		RTE_ETH_FOREACH_DEV(port_id) {
>> +			hotplug_list_add(rte_eth_devices[port_id].device,
>> +					 rte_eth_devices[port_id].data-
>>> kdrv);
>> +			eth_dev_event_callback_register(port_id);
>> +		}
>>   	}
>>
>>   	if (start_port(RTE_PORT_ALL) != 0)
>> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index
>> 8fde68d..c619e11 100644
>> --- a/app/test-pmd/testpmd.h
>> +++ b/app/test-pmd/testpmd.h
>> @@ -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_kernel_driver dev_kdrv;            /* kernel driver binded */
>> +};
>> +
>> +/** @internal Structure to keep track of registered callbacks */
>> +TAILQ_HEAD(hotplug_request_list, hotplug_request);
>> +
>>   enum {
>>   	PORT_TOPOLOGY_PAIRED,
>>   	PORT_TOPOLOGY_CHAINED,
>> --
>> 2.7.4

  reply	other threads:[~2018-04-13 10:48 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-03 18:17 [dpdk-dev] [PATCH V18 0/5] add hot plug failure and auto bind handler Jeff Guo
2018-04-03 18:17 ` [dpdk-dev] [PATCH V18 1/5] bus: introduce device hot unplug handle Jeff Guo
2018-04-04  4:31   ` Tan, Jianfeng
2018-04-06 10:54     ` Guo, Jia
2018-04-03 18:17 ` [dpdk-dev] [PATCH V18 2/5] bus/pci: implement handle hot unplug operation Jeff Guo
2018-04-04  5:25   ` Tan, Jianfeng
2018-04-06 10:57     ` Guo, Jia
2018-04-03 18:17 ` [dpdk-dev] [PATCH V18 3/5] eal: add failure handler mechanism for hot plug Jeff Guo
2018-04-04  2:58   ` Zhang, Qi Z
2018-04-06 10:53     ` Guo, Jia
2018-04-03 18:17 ` [dpdk-dev] [PATCH V18 4/5] eal: add driver auto bind for hot insertion Jeff Guo
2018-04-03 18:17 ` [dpdk-dev] [PATCH V18 5/5] app/testpmd: use auto handle for hotplug Jeff Guo
2018-04-06 10:56   ` [dpdk-dev] [PATCH V19 0/4] add hot plug failure and auto bind handler Jeff Guo
2018-04-06 10:56     ` [dpdk-dev] [PATCH V19 1/4] bus/pci: introduce device hot unplug handle Jeff Guo
2018-04-09 17:47       ` Ananyev, Konstantin
2018-04-11 11:37         ` Guo, Jia
2018-04-06 10:56     ` [dpdk-dev] [PATCH V19 2/4] eal: add failure handler mechanism for hot plug Jeff Guo
2018-04-06 14:03       ` Zhang, Qi Z
2018-04-06 14:24         ` Zhang, Qi Z
2018-04-11 11:50           ` Guo, Jia
2018-04-11 11:49         ` Guo, Jia
2018-04-09 17:42       ` Ananyev, Konstantin
2018-04-11 11:34         ` Guo, Jia
2018-04-06 10:56     ` [dpdk-dev] [PATCH V19 3/4] eal: add driver auto bind for hot insertion Jeff Guo
2018-04-06 10:56     ` [dpdk-dev] [PATCH V19 4/4] app/testpmd: use auto handle for hotplug Jeff Guo
2018-04-12  5:31       ` Matan Azrad
2018-04-13 10:48         ` Guo, Jia [this message]
2018-04-13 14:58           ` Matan Azrad

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=42450faf-7969-9238-823b-26fa144325ac@intel.com \
    --to=jia.guo@intel.com \
    --cc=bruce.richardson@intel.com \
    --cc=dev@dpdk.org \
    --cc=ferruh.yigit@intel.com \
    --cc=gaetan.rivet@6wind.com \
    --cc=harry.van.haaren@intel.com \
    --cc=helin.zhang@intel.com \
    --cc=jblunck@infradead.org \
    --cc=jianfeng.tan@intel.com \
    --cc=jingjing.wu@intel.com \
    --cc=konstantin.ananyev@intel.com \
    --cc=matan@mellanox.com \
    --cc=motih@mellanox.com \
    --cc=shreyansh.jain@nxp.com \
    --cc=stephen@networkplumber.org \
    --cc=thomas@monjalon.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).