xref: /dpdk/lib/eal/common/eal_common_proc.c (revision ae67895b507bb6af22263c79ba0d5c374b396485)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2016-2018 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
599a2dd95SBruce Richardson #include <dirent.h>
699a2dd95SBruce Richardson #include <errno.h>
799a2dd95SBruce Richardson #include <fcntl.h>
899a2dd95SBruce Richardson #include <fnmatch.h>
999a2dd95SBruce Richardson #include <inttypes.h>
1099a2dd95SBruce Richardson #include <libgen.h>
1199a2dd95SBruce Richardson #include <limits.h>
1299a2dd95SBruce Richardson #include <pthread.h>
1399a2dd95SBruce Richardson #include <stdio.h>
1499a2dd95SBruce Richardson #include <stdlib.h>
1599a2dd95SBruce Richardson #include <string.h>
1699a2dd95SBruce Richardson #include <sys/file.h>
1799a2dd95SBruce Richardson #include <sys/time.h>
1899a2dd95SBruce Richardson #include <sys/socket.h>
1999a2dd95SBruce Richardson #include <sys/un.h>
2099a2dd95SBruce Richardson #include <unistd.h>
2199a2dd95SBruce Richardson 
2299a2dd95SBruce Richardson #include <rte_alarm.h>
2399a2dd95SBruce Richardson #include <rte_common.h>
2499a2dd95SBruce Richardson #include <rte_cycles.h>
2599a2dd95SBruce Richardson #include <rte_eal.h>
2699a2dd95SBruce Richardson #include <rte_errno.h>
2799a2dd95SBruce Richardson #include <rte_lcore.h>
2899a2dd95SBruce Richardson #include <rte_log.h>
291c1abf17SThomas Monjalon #include <rte_thread.h>
3099a2dd95SBruce Richardson 
3199a2dd95SBruce Richardson #include "eal_memcfg.h"
3299a2dd95SBruce Richardson #include "eal_private.h"
3399a2dd95SBruce Richardson #include "eal_filesystem.h"
3499a2dd95SBruce Richardson #include "eal_internal_cfg.h"
3599a2dd95SBruce Richardson 
362a7a42a5STyler Retzlaff static RTE_ATOMIC(int) mp_fd = -1;
371c1abf17SThomas Monjalon static rte_thread_t mp_handle_tid;
3899a2dd95SBruce Richardson static char mp_filter[PATH_MAX];   /* Filter for secondary process sockets */
3999a2dd95SBruce Richardson static char mp_dir_path[PATH_MAX]; /* The directory path for all mp sockets */
4099a2dd95SBruce Richardson static pthread_mutex_t mp_mutex_action = PTHREAD_MUTEX_INITIALIZER;
4199a2dd95SBruce Richardson static char peer_name[PATH_MAX];
4299a2dd95SBruce Richardson 
4399a2dd95SBruce Richardson struct action_entry {
4499a2dd95SBruce Richardson 	TAILQ_ENTRY(action_entry) next;
4599a2dd95SBruce Richardson 	char action_name[RTE_MP_MAX_NAME_LEN];
4699a2dd95SBruce Richardson 	rte_mp_t action;
4799a2dd95SBruce Richardson };
4899a2dd95SBruce Richardson 
4999a2dd95SBruce Richardson /** Double linked list of actions. */
5099a2dd95SBruce Richardson TAILQ_HEAD(action_entry_list, action_entry);
5199a2dd95SBruce Richardson 
5299a2dd95SBruce Richardson static struct action_entry_list action_entry_list =
5399a2dd95SBruce Richardson 	TAILQ_HEAD_INITIALIZER(action_entry_list);
5499a2dd95SBruce Richardson 
5599a2dd95SBruce Richardson enum mp_type {
5699a2dd95SBruce Richardson 	MP_MSG, /* Share message with peers, will not block */
5799a2dd95SBruce Richardson 	MP_REQ, /* Request for information, Will block for a reply */
5899a2dd95SBruce Richardson 	MP_REP, /* Response to previously-received request */
5999a2dd95SBruce Richardson 	MP_IGN, /* Response telling requester to ignore this response */
6099a2dd95SBruce Richardson };
6199a2dd95SBruce Richardson 
6299a2dd95SBruce Richardson struct mp_msg_internal {
6399a2dd95SBruce Richardson 	int type;
6499a2dd95SBruce Richardson 	struct rte_mp_msg msg;
6599a2dd95SBruce Richardson };
6699a2dd95SBruce Richardson 
6799a2dd95SBruce Richardson struct async_request_param {
6899a2dd95SBruce Richardson 	rte_mp_async_reply_t clb;
6999a2dd95SBruce Richardson 	struct rte_mp_reply user_reply;
7099a2dd95SBruce Richardson 	struct timespec end;
7199a2dd95SBruce Richardson 	int n_responses_processed;
7299a2dd95SBruce Richardson };
7399a2dd95SBruce Richardson 
7499a2dd95SBruce Richardson struct pending_request {
7599a2dd95SBruce Richardson 	TAILQ_ENTRY(pending_request) next;
7699a2dd95SBruce Richardson 	enum {
7799a2dd95SBruce Richardson 		REQUEST_TYPE_SYNC,
7899a2dd95SBruce Richardson 		REQUEST_TYPE_ASYNC
7999a2dd95SBruce Richardson 	} type;
8099a2dd95SBruce Richardson 	char dst[PATH_MAX];
8199a2dd95SBruce Richardson 	struct rte_mp_msg *request;
8299a2dd95SBruce Richardson 	struct rte_mp_msg *reply;
8399a2dd95SBruce Richardson 	int reply_received;
8499a2dd95SBruce Richardson 	union {
8599a2dd95SBruce Richardson 		struct {
8699a2dd95SBruce Richardson 			struct async_request_param *param;
8799a2dd95SBruce Richardson 		} async;
8899a2dd95SBruce Richardson 		struct {
8999a2dd95SBruce Richardson 			pthread_cond_t cond;
9099a2dd95SBruce Richardson 		} sync;
9199a2dd95SBruce Richardson 	};
9299a2dd95SBruce Richardson };
9399a2dd95SBruce Richardson 
9499a2dd95SBruce Richardson TAILQ_HEAD(pending_request_list, pending_request);
9599a2dd95SBruce Richardson 
9699a2dd95SBruce Richardson static struct {
9799a2dd95SBruce Richardson 	struct pending_request_list requests;
9899a2dd95SBruce Richardson 	pthread_mutex_t lock;
9999a2dd95SBruce Richardson } pending_requests = {
10099a2dd95SBruce Richardson 	.requests = TAILQ_HEAD_INITIALIZER(pending_requests.requests),
10199a2dd95SBruce Richardson 	.lock = PTHREAD_MUTEX_INITIALIZER,
10299a2dd95SBruce Richardson 	/**< used in async requests only */
10399a2dd95SBruce Richardson };
10499a2dd95SBruce Richardson 
10599a2dd95SBruce Richardson /* forward declarations */
10699a2dd95SBruce Richardson static int
10799a2dd95SBruce Richardson mp_send(struct rte_mp_msg *msg, const char *peer, int type);
10899a2dd95SBruce Richardson 
10999a2dd95SBruce Richardson /* for use with alarm callback */
11099a2dd95SBruce Richardson static void
11199a2dd95SBruce Richardson async_reply_handle(void *arg);
11299a2dd95SBruce Richardson 
11399a2dd95SBruce Richardson /* for use with process_msg */
11499a2dd95SBruce Richardson static struct pending_request *
11599a2dd95SBruce Richardson async_reply_handle_thread_unsafe(void *arg);
11699a2dd95SBruce Richardson 
11799a2dd95SBruce Richardson static void
11899a2dd95SBruce Richardson trigger_async_action(struct pending_request *req);
11999a2dd95SBruce Richardson 
12099a2dd95SBruce Richardson static struct pending_request *
find_pending_request(const char * dst,const char * act_name)12199a2dd95SBruce Richardson find_pending_request(const char *dst, const char *act_name)
12299a2dd95SBruce Richardson {
12399a2dd95SBruce Richardson 	struct pending_request *r;
12499a2dd95SBruce Richardson 
12599a2dd95SBruce Richardson 	TAILQ_FOREACH(r, &pending_requests.requests, next) {
12699a2dd95SBruce Richardson 		if (!strcmp(r->dst, dst) &&
12799a2dd95SBruce Richardson 		    !strcmp(r->request->name, act_name))
12899a2dd95SBruce Richardson 			break;
12999a2dd95SBruce Richardson 	}
13099a2dd95SBruce Richardson 
13199a2dd95SBruce Richardson 	return r;
13299a2dd95SBruce Richardson }
13399a2dd95SBruce Richardson 
13499a2dd95SBruce Richardson static void
create_socket_path(const char * name,char * buf,int len)13599a2dd95SBruce Richardson create_socket_path(const char *name, char *buf, int len)
13699a2dd95SBruce Richardson {
13799a2dd95SBruce Richardson 	const char *prefix = eal_mp_socket_path();
13899a2dd95SBruce Richardson 
13999a2dd95SBruce Richardson 	if (strlen(name) > 0)
14099a2dd95SBruce Richardson 		snprintf(buf, len, "%s_%s", prefix, name);
14199a2dd95SBruce Richardson 	else
14299a2dd95SBruce Richardson 		strlcpy(buf, prefix, len);
14399a2dd95SBruce Richardson }
14499a2dd95SBruce Richardson 
14599a2dd95SBruce Richardson int
rte_eal_primary_proc_alive(const char * config_file_path)14699a2dd95SBruce Richardson rte_eal_primary_proc_alive(const char *config_file_path)
14799a2dd95SBruce Richardson {
14899a2dd95SBruce Richardson 	int config_fd;
14999a2dd95SBruce Richardson 
15099a2dd95SBruce Richardson 	if (config_file_path)
15199a2dd95SBruce Richardson 		config_fd = open(config_file_path, O_RDONLY);
15299a2dd95SBruce Richardson 	else {
15399a2dd95SBruce Richardson 		const char *path;
15499a2dd95SBruce Richardson 
15599a2dd95SBruce Richardson 		path = eal_runtime_config_path();
15699a2dd95SBruce Richardson 		config_fd = open(path, O_RDONLY);
15799a2dd95SBruce Richardson 	}
15899a2dd95SBruce Richardson 	if (config_fd < 0)
15999a2dd95SBruce Richardson 		return 0;
16099a2dd95SBruce Richardson 
16199a2dd95SBruce Richardson 	int ret = lockf(config_fd, F_TEST, 0);
16299a2dd95SBruce Richardson 	close(config_fd);
16399a2dd95SBruce Richardson 
16499a2dd95SBruce Richardson 	return !!ret;
16599a2dd95SBruce Richardson }
16699a2dd95SBruce Richardson 
16799a2dd95SBruce Richardson static struct action_entry *
find_action_entry_by_name(const char * name)16899a2dd95SBruce Richardson find_action_entry_by_name(const char *name)
16999a2dd95SBruce Richardson {
17099a2dd95SBruce Richardson 	struct action_entry *entry;
17199a2dd95SBruce Richardson 
17299a2dd95SBruce Richardson 	TAILQ_FOREACH(entry, &action_entry_list, next) {
17399a2dd95SBruce Richardson 		if (strncmp(entry->action_name, name, RTE_MP_MAX_NAME_LEN) == 0)
17499a2dd95SBruce Richardson 			break;
17599a2dd95SBruce Richardson 	}
17699a2dd95SBruce Richardson 
17799a2dd95SBruce Richardson 	return entry;
17899a2dd95SBruce Richardson }
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson static int
validate_action_name(const char * name)18199a2dd95SBruce Richardson validate_action_name(const char *name)
18299a2dd95SBruce Richardson {
18399a2dd95SBruce Richardson 	if (name == NULL) {
184*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Action name cannot be NULL");
18599a2dd95SBruce Richardson 		rte_errno = EINVAL;
18699a2dd95SBruce Richardson 		return -1;
18799a2dd95SBruce Richardson 	}
18899a2dd95SBruce Richardson 	if (strnlen(name, RTE_MP_MAX_NAME_LEN) == 0) {
189*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Length of action name is zero");
19099a2dd95SBruce Richardson 		rte_errno = EINVAL;
19199a2dd95SBruce Richardson 		return -1;
19299a2dd95SBruce Richardson 	}
19399a2dd95SBruce Richardson 	if (strnlen(name, RTE_MP_MAX_NAME_LEN) == RTE_MP_MAX_NAME_LEN) {
19499a2dd95SBruce Richardson 		rte_errno = E2BIG;
19599a2dd95SBruce Richardson 		return -1;
19699a2dd95SBruce Richardson 	}
19799a2dd95SBruce Richardson 	return 0;
19899a2dd95SBruce Richardson }
19999a2dd95SBruce Richardson 
20099a2dd95SBruce Richardson int
rte_mp_action_register(const char * name,rte_mp_t action)20199a2dd95SBruce Richardson rte_mp_action_register(const char *name, rte_mp_t action)
20299a2dd95SBruce Richardson {
20399a2dd95SBruce Richardson 	struct action_entry *entry;
20499a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
20599a2dd95SBruce Richardson 		eal_get_internal_configuration();
20699a2dd95SBruce Richardson 
20799a2dd95SBruce Richardson 	if (validate_action_name(name) != 0)
20899a2dd95SBruce Richardson 		return -1;
20999a2dd95SBruce Richardson 
21099a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
211*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "No shared files mode enabled, IPC is disabled");
21299a2dd95SBruce Richardson 		rte_errno = ENOTSUP;
21399a2dd95SBruce Richardson 		return -1;
21499a2dd95SBruce Richardson 	}
21599a2dd95SBruce Richardson 
21699a2dd95SBruce Richardson 	entry = malloc(sizeof(struct action_entry));
21799a2dd95SBruce Richardson 	if (entry == NULL) {
21899a2dd95SBruce Richardson 		rte_errno = ENOMEM;
21999a2dd95SBruce Richardson 		return -1;
22099a2dd95SBruce Richardson 	}
22199a2dd95SBruce Richardson 	strlcpy(entry->action_name, name, sizeof(entry->action_name));
22299a2dd95SBruce Richardson 	entry->action = action;
22399a2dd95SBruce Richardson 
22499a2dd95SBruce Richardson 	pthread_mutex_lock(&mp_mutex_action);
22599a2dd95SBruce Richardson 	if (find_action_entry_by_name(name) != NULL) {
22699a2dd95SBruce Richardson 		pthread_mutex_unlock(&mp_mutex_action);
22799a2dd95SBruce Richardson 		rte_errno = EEXIST;
22899a2dd95SBruce Richardson 		free(entry);
22999a2dd95SBruce Richardson 		return -1;
23099a2dd95SBruce Richardson 	}
23199a2dd95SBruce Richardson 	TAILQ_INSERT_TAIL(&action_entry_list, entry, next);
23299a2dd95SBruce Richardson 	pthread_mutex_unlock(&mp_mutex_action);
23399a2dd95SBruce Richardson 	return 0;
23499a2dd95SBruce Richardson }
23599a2dd95SBruce Richardson 
23699a2dd95SBruce Richardson void
rte_mp_action_unregister(const char * name)23799a2dd95SBruce Richardson rte_mp_action_unregister(const char *name)
23899a2dd95SBruce Richardson {
23999a2dd95SBruce Richardson 	struct action_entry *entry;
24099a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
24199a2dd95SBruce Richardson 		eal_get_internal_configuration();
24299a2dd95SBruce Richardson 
24399a2dd95SBruce Richardson 	if (validate_action_name(name) != 0)
24499a2dd95SBruce Richardson 		return;
24599a2dd95SBruce Richardson 
24699a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
247*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "No shared files mode enabled, IPC is disabled");
24899a2dd95SBruce Richardson 		return;
24999a2dd95SBruce Richardson 	}
25099a2dd95SBruce Richardson 
25199a2dd95SBruce Richardson 	pthread_mutex_lock(&mp_mutex_action);
25299a2dd95SBruce Richardson 	entry = find_action_entry_by_name(name);
25399a2dd95SBruce Richardson 	if (entry == NULL) {
25499a2dd95SBruce Richardson 		pthread_mutex_unlock(&mp_mutex_action);
25599a2dd95SBruce Richardson 		return;
25699a2dd95SBruce Richardson 	}
25799a2dd95SBruce Richardson 	TAILQ_REMOVE(&action_entry_list, entry, next);
25899a2dd95SBruce Richardson 	pthread_mutex_unlock(&mp_mutex_action);
25999a2dd95SBruce Richardson 	free(entry);
26099a2dd95SBruce Richardson }
26199a2dd95SBruce Richardson 
26299a2dd95SBruce Richardson static int
read_msg(int fd,struct mp_msg_internal * m,struct sockaddr_un * s)263668958f3SStephen Hemminger read_msg(int fd, struct mp_msg_internal *m, struct sockaddr_un *s)
26499a2dd95SBruce Richardson {
26599a2dd95SBruce Richardson 	int msglen;
26699a2dd95SBruce Richardson 	struct iovec iov;
26799a2dd95SBruce Richardson 	struct msghdr msgh;
26899a2dd95SBruce Richardson 	char control[CMSG_SPACE(sizeof(m->msg.fds))];
26999a2dd95SBruce Richardson 	struct cmsghdr *cmsg;
27099a2dd95SBruce Richardson 	int buflen = sizeof(*m) - sizeof(m->msg.fds);
27199a2dd95SBruce Richardson 
27299a2dd95SBruce Richardson 	memset(&msgh, 0, sizeof(msgh));
27399a2dd95SBruce Richardson 	iov.iov_base = m;
27499a2dd95SBruce Richardson 	iov.iov_len  = buflen;
27599a2dd95SBruce Richardson 
27699a2dd95SBruce Richardson 	msgh.msg_name = s;
27799a2dd95SBruce Richardson 	msgh.msg_namelen = sizeof(*s);
27899a2dd95SBruce Richardson 	msgh.msg_iov = &iov;
27999a2dd95SBruce Richardson 	msgh.msg_iovlen = 1;
28099a2dd95SBruce Richardson 	msgh.msg_control = control;
28199a2dd95SBruce Richardson 	msgh.msg_controllen = sizeof(control);
28299a2dd95SBruce Richardson 
2836e858b4dSStephen Hemminger retry:
284668958f3SStephen Hemminger 	msglen = recvmsg(fd, &msgh, 0);
2856e858b4dSStephen Hemminger 
2866e858b4dSStephen Hemminger 	/* zero length message means socket was closed */
2876e858b4dSStephen Hemminger 	if (msglen == 0)
2886e858b4dSStephen Hemminger 		return 0;
2896e858b4dSStephen Hemminger 
29099a2dd95SBruce Richardson 	if (msglen < 0) {
2916e858b4dSStephen Hemminger 		if (errno == EINTR)
2926e858b4dSStephen Hemminger 			goto retry;
2936e858b4dSStephen Hemminger 
294*ae67895bSDavid Marchand 		EAL_LOG(ERR, "recvmsg failed, %s", strerror(errno));
29599a2dd95SBruce Richardson 		return -1;
29699a2dd95SBruce Richardson 	}
29799a2dd95SBruce Richardson 
29899a2dd95SBruce Richardson 	if (msglen != buflen || (msgh.msg_flags & (MSG_TRUNC | MSG_CTRUNC))) {
299*ae67895bSDavid Marchand 		EAL_LOG(ERR, "truncated msg");
30099a2dd95SBruce Richardson 		return -1;
30199a2dd95SBruce Richardson 	}
30299a2dd95SBruce Richardson 
30399a2dd95SBruce Richardson 	/* read auxiliary FDs if any */
30499a2dd95SBruce Richardson 	for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
30599a2dd95SBruce Richardson 		cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
30699a2dd95SBruce Richardson 		if ((cmsg->cmsg_level == SOL_SOCKET) &&
30799a2dd95SBruce Richardson 			(cmsg->cmsg_type == SCM_RIGHTS)) {
30899a2dd95SBruce Richardson 			memcpy(m->msg.fds, CMSG_DATA(cmsg), sizeof(m->msg.fds));
30999a2dd95SBruce Richardson 			break;
31099a2dd95SBruce Richardson 		}
31199a2dd95SBruce Richardson 	}
31299a2dd95SBruce Richardson 	/* sanity-check the response */
31399a2dd95SBruce Richardson 	if (m->msg.num_fds < 0 || m->msg.num_fds > RTE_MP_MAX_FD_NUM) {
314*ae67895bSDavid Marchand 		EAL_LOG(ERR, "invalid number of fd's received");
31599a2dd95SBruce Richardson 		return -1;
31699a2dd95SBruce Richardson 	}
31799a2dd95SBruce Richardson 	if (m->msg.len_param < 0 || m->msg.len_param > RTE_MP_MAX_PARAM_LEN) {
318*ae67895bSDavid Marchand 		EAL_LOG(ERR, "invalid received data length");
31999a2dd95SBruce Richardson 		return -1;
32099a2dd95SBruce Richardson 	}
3216e858b4dSStephen Hemminger 	return msglen;
32299a2dd95SBruce Richardson }
32399a2dd95SBruce Richardson 
32499a2dd95SBruce Richardson static void
cleanup_msg_fds(const struct rte_mp_msg * msg)325a64a4564SViacheslav Ovsiienko cleanup_msg_fds(const struct rte_mp_msg *msg)
326a64a4564SViacheslav Ovsiienko {
327a64a4564SViacheslav Ovsiienko 	int i;
328a64a4564SViacheslav Ovsiienko 
329a64a4564SViacheslav Ovsiienko 	for (i = 0; i < msg->num_fds; i++)
330a64a4564SViacheslav Ovsiienko 		close(msg->fds[i]);
331a64a4564SViacheslav Ovsiienko }
332a64a4564SViacheslav Ovsiienko 
333a64a4564SViacheslav Ovsiienko static void
process_msg(struct mp_msg_internal * m,struct sockaddr_un * s)33499a2dd95SBruce Richardson process_msg(struct mp_msg_internal *m, struct sockaddr_un *s)
33599a2dd95SBruce Richardson {
33699a2dd95SBruce Richardson 	struct pending_request *pending_req;
33799a2dd95SBruce Richardson 	struct action_entry *entry;
33899a2dd95SBruce Richardson 	struct rte_mp_msg *msg = &m->msg;
33999a2dd95SBruce Richardson 	rte_mp_t action = NULL;
34099a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
34199a2dd95SBruce Richardson 		eal_get_internal_configuration();
34299a2dd95SBruce Richardson 
343*ae67895bSDavid Marchand 	EAL_LOG(DEBUG, "msg: %s", msg->name);
34499a2dd95SBruce Richardson 
34599a2dd95SBruce Richardson 	if (m->type == MP_REP || m->type == MP_IGN) {
34699a2dd95SBruce Richardson 		struct pending_request *req = NULL;
34799a2dd95SBruce Richardson 
34899a2dd95SBruce Richardson 		pthread_mutex_lock(&pending_requests.lock);
34999a2dd95SBruce Richardson 		pending_req = find_pending_request(s->sun_path, msg->name);
35099a2dd95SBruce Richardson 		if (pending_req) {
35199a2dd95SBruce Richardson 			memcpy(pending_req->reply, msg, sizeof(*msg));
35299a2dd95SBruce Richardson 			/* -1 indicates that we've been asked to ignore */
35399a2dd95SBruce Richardson 			pending_req->reply_received =
35499a2dd95SBruce Richardson 				m->type == MP_REP ? 1 : -1;
35599a2dd95SBruce Richardson 
35699a2dd95SBruce Richardson 			if (pending_req->type == REQUEST_TYPE_SYNC)
35799a2dd95SBruce Richardson 				pthread_cond_signal(&pending_req->sync.cond);
35899a2dd95SBruce Richardson 			else if (pending_req->type == REQUEST_TYPE_ASYNC)
35999a2dd95SBruce Richardson 				req = async_reply_handle_thread_unsafe(
36099a2dd95SBruce Richardson 						pending_req);
361a64a4564SViacheslav Ovsiienko 		} else {
362*ae67895bSDavid Marchand 			EAL_LOG(ERR, "Drop mp reply: %s", msg->name);
363a64a4564SViacheslav Ovsiienko 			cleanup_msg_fds(msg);
364a64a4564SViacheslav Ovsiienko 		}
36599a2dd95SBruce Richardson 		pthread_mutex_unlock(&pending_requests.lock);
36699a2dd95SBruce Richardson 
36799a2dd95SBruce Richardson 		if (req != NULL)
36899a2dd95SBruce Richardson 			trigger_async_action(req);
36999a2dd95SBruce Richardson 		return;
37099a2dd95SBruce Richardson 	}
37199a2dd95SBruce Richardson 
37299a2dd95SBruce Richardson 	pthread_mutex_lock(&mp_mutex_action);
37399a2dd95SBruce Richardson 	entry = find_action_entry_by_name(msg->name);
37499a2dd95SBruce Richardson 	if (entry != NULL)
37599a2dd95SBruce Richardson 		action = entry->action;
37699a2dd95SBruce Richardson 	pthread_mutex_unlock(&mp_mutex_action);
37799a2dd95SBruce Richardson 
37899a2dd95SBruce Richardson 	if (!action) {
37999a2dd95SBruce Richardson 		if (m->type == MP_REQ && !internal_conf->init_complete) {
38099a2dd95SBruce Richardson 			/* if this is a request, and init is not yet complete,
38199a2dd95SBruce Richardson 			 * and callback wasn't registered, we should tell the
38299a2dd95SBruce Richardson 			 * requester to ignore our existence because we're not
38399a2dd95SBruce Richardson 			 * yet ready to process this request.
38499a2dd95SBruce Richardson 			 */
38599a2dd95SBruce Richardson 			struct rte_mp_msg dummy;
38699a2dd95SBruce Richardson 
38799a2dd95SBruce Richardson 			memset(&dummy, 0, sizeof(dummy));
38899a2dd95SBruce Richardson 			strlcpy(dummy.name, msg->name, sizeof(dummy.name));
38999a2dd95SBruce Richardson 			mp_send(&dummy, s->sun_path, MP_IGN);
39099a2dd95SBruce Richardson 		} else {
391*ae67895bSDavid Marchand 			EAL_LOG(ERR, "Cannot find action: %s",
39299a2dd95SBruce Richardson 				msg->name);
39399a2dd95SBruce Richardson 		}
394a64a4564SViacheslav Ovsiienko 		cleanup_msg_fds(msg);
39599a2dd95SBruce Richardson 	} else if (action(msg, s->sun_path) < 0) {
396*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Fail to handle message: %s", msg->name);
39799a2dd95SBruce Richardson 	}
39899a2dd95SBruce Richardson }
39999a2dd95SBruce Richardson 
4001c1abf17SThomas Monjalon static uint32_t
mp_handle(void * arg __rte_unused)40199a2dd95SBruce Richardson mp_handle(void *arg __rte_unused)
40299a2dd95SBruce Richardson {
40399a2dd95SBruce Richardson 	struct mp_msg_internal msg;
40499a2dd95SBruce Richardson 	struct sockaddr_un sa;
405668958f3SStephen Hemminger 	int fd;
40699a2dd95SBruce Richardson 
4072a7a42a5STyler Retzlaff 	while ((fd = rte_atomic_load_explicit(&mp_fd, rte_memory_order_relaxed)) >= 0) {
4086e858b4dSStephen Hemminger 		int ret;
4096e858b4dSStephen Hemminger 
410668958f3SStephen Hemminger 		ret = read_msg(fd, &msg, &sa);
4116e858b4dSStephen Hemminger 		if (ret <= 0)
4126e858b4dSStephen Hemminger 			break;
4136e858b4dSStephen Hemminger 
41499a2dd95SBruce Richardson 		process_msg(&msg, &sa);
41599a2dd95SBruce Richardson 	}
41699a2dd95SBruce Richardson 
4171c1abf17SThomas Monjalon 	return 0;
41899a2dd95SBruce Richardson }
41999a2dd95SBruce Richardson 
42099a2dd95SBruce Richardson static int
timespec_cmp(const struct timespec * a,const struct timespec * b)42199a2dd95SBruce Richardson timespec_cmp(const struct timespec *a, const struct timespec *b)
42299a2dd95SBruce Richardson {
42399a2dd95SBruce Richardson 	if (a->tv_sec < b->tv_sec)
42499a2dd95SBruce Richardson 		return -1;
42599a2dd95SBruce Richardson 	if (a->tv_sec > b->tv_sec)
42699a2dd95SBruce Richardson 		return 1;
42799a2dd95SBruce Richardson 	if (a->tv_nsec < b->tv_nsec)
42899a2dd95SBruce Richardson 		return -1;
42999a2dd95SBruce Richardson 	if (a->tv_nsec > b->tv_nsec)
43099a2dd95SBruce Richardson 		return 1;
43199a2dd95SBruce Richardson 	return 0;
43299a2dd95SBruce Richardson }
43399a2dd95SBruce Richardson 
43499a2dd95SBruce Richardson enum async_action {
43599a2dd95SBruce Richardson 	ACTION_FREE, /**< free the action entry, but don't trigger callback */
43699a2dd95SBruce Richardson 	ACTION_TRIGGER /**< trigger callback, then free action entry */
43799a2dd95SBruce Richardson };
43899a2dd95SBruce Richardson 
43999a2dd95SBruce Richardson static enum async_action
process_async_request(struct pending_request * sr,const struct timespec * now)44099a2dd95SBruce Richardson process_async_request(struct pending_request *sr, const struct timespec *now)
44199a2dd95SBruce Richardson {
44299a2dd95SBruce Richardson 	struct async_request_param *param;
44399a2dd95SBruce Richardson 	struct rte_mp_reply *reply;
44499a2dd95SBruce Richardson 	bool timeout, last_msg;
44599a2dd95SBruce Richardson 
44699a2dd95SBruce Richardson 	param = sr->async.param;
44799a2dd95SBruce Richardson 	reply = &param->user_reply;
44899a2dd95SBruce Richardson 
44999a2dd95SBruce Richardson 	/* did we timeout? */
45099a2dd95SBruce Richardson 	timeout = timespec_cmp(&param->end, now) <= 0;
45199a2dd95SBruce Richardson 
45299a2dd95SBruce Richardson 	/* if we received a response, adjust relevant data and copy message. */
45399a2dd95SBruce Richardson 	if (sr->reply_received == 1 && sr->reply) {
45499a2dd95SBruce Richardson 		struct rte_mp_msg *msg, *user_msgs, *tmp;
45599a2dd95SBruce Richardson 
45699a2dd95SBruce Richardson 		msg = sr->reply;
45799a2dd95SBruce Richardson 		user_msgs = reply->msgs;
45899a2dd95SBruce Richardson 
45999a2dd95SBruce Richardson 		tmp = realloc(user_msgs, sizeof(*msg) *
46099a2dd95SBruce Richardson 				(reply->nb_received + 1));
46199a2dd95SBruce Richardson 		if (!tmp) {
462*ae67895bSDavid Marchand 			EAL_LOG(ERR, "Fail to alloc reply for request %s:%s",
46399a2dd95SBruce Richardson 				sr->dst, sr->request->name);
46499a2dd95SBruce Richardson 			/* this entry is going to be removed and its message
46599a2dd95SBruce Richardson 			 * dropped, but we don't want to leak memory, so
46699a2dd95SBruce Richardson 			 * continue.
46799a2dd95SBruce Richardson 			 */
46899a2dd95SBruce Richardson 		} else {
46999a2dd95SBruce Richardson 			user_msgs = tmp;
47099a2dd95SBruce Richardson 			reply->msgs = user_msgs;
47199a2dd95SBruce Richardson 			memcpy(&user_msgs[reply->nb_received],
47299a2dd95SBruce Richardson 					msg, sizeof(*msg));
47399a2dd95SBruce Richardson 			reply->nb_received++;
47499a2dd95SBruce Richardson 		}
47599a2dd95SBruce Richardson 
47699a2dd95SBruce Richardson 		/* mark this request as processed */
47799a2dd95SBruce Richardson 		param->n_responses_processed++;
47899a2dd95SBruce Richardson 	} else if (sr->reply_received == -1) {
47999a2dd95SBruce Richardson 		/* we were asked to ignore this process */
48099a2dd95SBruce Richardson 		reply->nb_sent--;
48199a2dd95SBruce Richardson 	} else if (timeout) {
48299a2dd95SBruce Richardson 		/* count it as processed response, but don't increment
48399a2dd95SBruce Richardson 		 * nb_received.
48499a2dd95SBruce Richardson 		 */
48599a2dd95SBruce Richardson 		param->n_responses_processed++;
48699a2dd95SBruce Richardson 	}
48799a2dd95SBruce Richardson 
48899a2dd95SBruce Richardson 	free(sr->reply);
48999a2dd95SBruce Richardson 
49099a2dd95SBruce Richardson 	last_msg = param->n_responses_processed == reply->nb_sent;
49199a2dd95SBruce Richardson 
49299a2dd95SBruce Richardson 	return last_msg ? ACTION_TRIGGER : ACTION_FREE;
49399a2dd95SBruce Richardson }
49499a2dd95SBruce Richardson 
49599a2dd95SBruce Richardson static void
trigger_async_action(struct pending_request * sr)49699a2dd95SBruce Richardson trigger_async_action(struct pending_request *sr)
49799a2dd95SBruce Richardson {
49899a2dd95SBruce Richardson 	struct async_request_param *param;
49999a2dd95SBruce Richardson 	struct rte_mp_reply *reply;
50099a2dd95SBruce Richardson 
50199a2dd95SBruce Richardson 	param = sr->async.param;
50299a2dd95SBruce Richardson 	reply = &param->user_reply;
50399a2dd95SBruce Richardson 
50499a2dd95SBruce Richardson 	param->clb(sr->request, reply);
50599a2dd95SBruce Richardson 
50699a2dd95SBruce Richardson 	/* clean up */
50799a2dd95SBruce Richardson 	free(sr->async.param->user_reply.msgs);
50899a2dd95SBruce Richardson 	free(sr->async.param);
50999a2dd95SBruce Richardson 	free(sr->request);
51099a2dd95SBruce Richardson 	free(sr);
51199a2dd95SBruce Richardson }
51299a2dd95SBruce Richardson 
51399a2dd95SBruce Richardson static struct pending_request *
async_reply_handle_thread_unsafe(void * arg)51499a2dd95SBruce Richardson async_reply_handle_thread_unsafe(void *arg)
51599a2dd95SBruce Richardson {
51699a2dd95SBruce Richardson 	struct pending_request *req = (struct pending_request *)arg;
51799a2dd95SBruce Richardson 	enum async_action action;
51899a2dd95SBruce Richardson 	struct timespec ts_now;
51999a2dd95SBruce Richardson 
520cc994d39SChengwen Feng 	if (clock_gettime(CLOCK_MONOTONIC, &ts_now) < 0) {
521*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Cannot get current time");
52299a2dd95SBruce Richardson 		goto no_trigger;
52399a2dd95SBruce Richardson 	}
52499a2dd95SBruce Richardson 
52599a2dd95SBruce Richardson 	action = process_async_request(req, &ts_now);
52699a2dd95SBruce Richardson 
52799a2dd95SBruce Richardson 	TAILQ_REMOVE(&pending_requests.requests, req, next);
52899a2dd95SBruce Richardson 
52999a2dd95SBruce Richardson 	if (rte_eal_alarm_cancel(async_reply_handle, req) < 0) {
53099a2dd95SBruce Richardson 		/* if we failed to cancel the alarm because it's already in
53199a2dd95SBruce Richardson 		 * progress, don't proceed because otherwise we will end up
53299a2dd95SBruce Richardson 		 * handling the same message twice.
53399a2dd95SBruce Richardson 		 */
53499a2dd95SBruce Richardson 		if (rte_errno == EINPROGRESS) {
535*ae67895bSDavid Marchand 			EAL_LOG(DEBUG, "Request handling is already in progress");
53699a2dd95SBruce Richardson 			goto no_trigger;
53799a2dd95SBruce Richardson 		}
538*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Failed to cancel alarm");
53999a2dd95SBruce Richardson 	}
54099a2dd95SBruce Richardson 
54199a2dd95SBruce Richardson 	if (action == ACTION_TRIGGER)
54299a2dd95SBruce Richardson 		return req;
54399a2dd95SBruce Richardson no_trigger:
54499a2dd95SBruce Richardson 	free(req);
54599a2dd95SBruce Richardson 	return NULL;
54699a2dd95SBruce Richardson }
54799a2dd95SBruce Richardson 
54899a2dd95SBruce Richardson static void
async_reply_handle(void * arg)54999a2dd95SBruce Richardson async_reply_handle(void *arg)
55099a2dd95SBruce Richardson {
55199a2dd95SBruce Richardson 	struct pending_request *req;
55299a2dd95SBruce Richardson 
55399a2dd95SBruce Richardson 	pthread_mutex_lock(&pending_requests.lock);
55499a2dd95SBruce Richardson 	req = async_reply_handle_thread_unsafe(arg);
55599a2dd95SBruce Richardson 	pthread_mutex_unlock(&pending_requests.lock);
55699a2dd95SBruce Richardson 
55799a2dd95SBruce Richardson 	if (req != NULL)
55899a2dd95SBruce Richardson 		trigger_async_action(req);
55999a2dd95SBruce Richardson }
56099a2dd95SBruce Richardson 
56199a2dd95SBruce Richardson static int
open_socket_fd(void)56299a2dd95SBruce Richardson open_socket_fd(void)
56399a2dd95SBruce Richardson {
56499a2dd95SBruce Richardson 	struct sockaddr_un un;
56599a2dd95SBruce Richardson 
56699a2dd95SBruce Richardson 	peer_name[0] = '\0';
56799a2dd95SBruce Richardson 	if (rte_eal_process_type() == RTE_PROC_SECONDARY)
56899a2dd95SBruce Richardson 		snprintf(peer_name, sizeof(peer_name),
56999a2dd95SBruce Richardson 				"%d_%"PRIx64, getpid(), rte_rdtsc());
57099a2dd95SBruce Richardson 
57199a2dd95SBruce Richardson 	mp_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
57299a2dd95SBruce Richardson 	if (mp_fd < 0) {
573*ae67895bSDavid Marchand 		EAL_LOG(ERR, "failed to create unix socket");
57499a2dd95SBruce Richardson 		return -1;
57599a2dd95SBruce Richardson 	}
57699a2dd95SBruce Richardson 
57799a2dd95SBruce Richardson 	memset(&un, 0, sizeof(un));
57899a2dd95SBruce Richardson 	un.sun_family = AF_UNIX;
57999a2dd95SBruce Richardson 
58099a2dd95SBruce Richardson 	create_socket_path(peer_name, un.sun_path, sizeof(un.sun_path));
58199a2dd95SBruce Richardson 
58299a2dd95SBruce Richardson 	unlink(un.sun_path); /* May still exist since last run */
58399a2dd95SBruce Richardson 
58499a2dd95SBruce Richardson 	if (bind(mp_fd, (struct sockaddr *)&un, sizeof(un)) < 0) {
585*ae67895bSDavid Marchand 		EAL_LOG(ERR, "failed to bind %s: %s",
58699a2dd95SBruce Richardson 			un.sun_path, strerror(errno));
58799a2dd95SBruce Richardson 		close(mp_fd);
58899a2dd95SBruce Richardson 		return -1;
58999a2dd95SBruce Richardson 	}
59099a2dd95SBruce Richardson 
591*ae67895bSDavid Marchand 	EAL_LOG(INFO, "Multi-process socket %s", un.sun_path);
59299a2dd95SBruce Richardson 	return mp_fd;
59399a2dd95SBruce Richardson }
59499a2dd95SBruce Richardson 
59599a2dd95SBruce Richardson static void
close_socket_fd(int fd)596e7885281SDavid Marchand close_socket_fd(int fd)
59799a2dd95SBruce Richardson {
59899a2dd95SBruce Richardson 	char path[PATH_MAX];
59999a2dd95SBruce Richardson 
600e7885281SDavid Marchand 	close(fd);
60199a2dd95SBruce Richardson 	create_socket_path(peer_name, path, sizeof(path));
60299a2dd95SBruce Richardson 	unlink(path);
60399a2dd95SBruce Richardson }
60499a2dd95SBruce Richardson 
60599a2dd95SBruce Richardson int
rte_mp_channel_init(void)60699a2dd95SBruce Richardson rte_mp_channel_init(void)
60799a2dd95SBruce Richardson {
60899a2dd95SBruce Richardson 	char path[PATH_MAX];
60999a2dd95SBruce Richardson 	int dir_fd;
61099a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
61199a2dd95SBruce Richardson 		eal_get_internal_configuration();
61299a2dd95SBruce Richardson 
61399a2dd95SBruce Richardson 	/* in no shared files mode, we do not have secondary processes support,
61499a2dd95SBruce Richardson 	 * so no need to initialize IPC.
61599a2dd95SBruce Richardson 	 */
61699a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
617*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "No shared files mode enabled, IPC will be disabled");
61899a2dd95SBruce Richardson 		rte_errno = ENOTSUP;
61999a2dd95SBruce Richardson 		return -1;
62099a2dd95SBruce Richardson 	}
62199a2dd95SBruce Richardson 
62299a2dd95SBruce Richardson 	/* create filter path */
62399a2dd95SBruce Richardson 	create_socket_path("*", path, sizeof(path));
62499a2dd95SBruce Richardson 	strlcpy(mp_filter, basename(path), sizeof(mp_filter));
62599a2dd95SBruce Richardson 
62699a2dd95SBruce Richardson 	/* path may have been modified, so recreate it */
62799a2dd95SBruce Richardson 	create_socket_path("*", path, sizeof(path));
62899a2dd95SBruce Richardson 	strlcpy(mp_dir_path, dirname(path), sizeof(mp_dir_path));
62999a2dd95SBruce Richardson 
63099a2dd95SBruce Richardson 	/* lock the directory */
63199a2dd95SBruce Richardson 	dir_fd = open(mp_dir_path, O_RDONLY);
63299a2dd95SBruce Richardson 	if (dir_fd < 0) {
633*ae67895bSDavid Marchand 		EAL_LOG(ERR, "failed to open %s: %s",
63499a2dd95SBruce Richardson 			mp_dir_path, strerror(errno));
63599a2dd95SBruce Richardson 		return -1;
63699a2dd95SBruce Richardson 	}
63799a2dd95SBruce Richardson 
63899a2dd95SBruce Richardson 	if (flock(dir_fd, LOCK_EX)) {
639*ae67895bSDavid Marchand 		EAL_LOG(ERR, "failed to lock %s: %s",
64099a2dd95SBruce Richardson 			mp_dir_path, strerror(errno));
64199a2dd95SBruce Richardson 		close(dir_fd);
64299a2dd95SBruce Richardson 		return -1;
64399a2dd95SBruce Richardson 	}
64499a2dd95SBruce Richardson 
64599a2dd95SBruce Richardson 	if (open_socket_fd() < 0) {
64699a2dd95SBruce Richardson 		close(dir_fd);
64799a2dd95SBruce Richardson 		return -1;
64899a2dd95SBruce Richardson 	}
64999a2dd95SBruce Richardson 
6501c1abf17SThomas Monjalon 	if (rte_thread_create_internal_control(&mp_handle_tid, "mp-msg",
6511c1abf17SThomas Monjalon 			mp_handle, NULL) < 0) {
652*ae67895bSDavid Marchand 		EAL_LOG(ERR, "failed to create mp thread: %s",
65399a2dd95SBruce Richardson 			strerror(errno));
65499a2dd95SBruce Richardson 		close(dir_fd);
6552a7a42a5STyler Retzlaff 		close(rte_atomic_exchange_explicit(&mp_fd, -1, rte_memory_order_relaxed));
65699a2dd95SBruce Richardson 		return -1;
65799a2dd95SBruce Richardson 	}
65899a2dd95SBruce Richardson 
65999a2dd95SBruce Richardson 	/* unlock the directory */
66099a2dd95SBruce Richardson 	flock(dir_fd, LOCK_UN);
66199a2dd95SBruce Richardson 	close(dir_fd);
66299a2dd95SBruce Richardson 
66399a2dd95SBruce Richardson 	return 0;
66499a2dd95SBruce Richardson }
66599a2dd95SBruce Richardson 
66699a2dd95SBruce Richardson void
rte_mp_channel_cleanup(void)66799a2dd95SBruce Richardson rte_mp_channel_cleanup(void)
66899a2dd95SBruce Richardson {
669e7885281SDavid Marchand 	int fd;
670e7885281SDavid Marchand 
6712a7a42a5STyler Retzlaff 	fd = rte_atomic_exchange_explicit(&mp_fd, -1, rte_memory_order_relaxed);
672668958f3SStephen Hemminger 	if (fd < 0)
673e7885281SDavid Marchand 		return;
674e7885281SDavid Marchand 
6751c1abf17SThomas Monjalon 	pthread_cancel((pthread_t)mp_handle_tid.opaque_id);
6761c1abf17SThomas Monjalon 	rte_thread_join(mp_handle_tid, NULL);
677e7885281SDavid Marchand 	close_socket_fd(fd);
67899a2dd95SBruce Richardson }
67999a2dd95SBruce Richardson 
68099a2dd95SBruce Richardson /**
68199a2dd95SBruce Richardson  * Return -1, as fail to send message and it's caused by the local side.
68299a2dd95SBruce Richardson  * Return 0, as fail to send message and it's caused by the remote side.
68399a2dd95SBruce Richardson  * Return 1, as succeed to send message.
68499a2dd95SBruce Richardson  */
68599a2dd95SBruce Richardson static int
send_msg(const char * dst_path,struct rte_mp_msg * msg,int type)68699a2dd95SBruce Richardson send_msg(const char *dst_path, struct rte_mp_msg *msg, int type)
68799a2dd95SBruce Richardson {
68899a2dd95SBruce Richardson 	int snd;
68999a2dd95SBruce Richardson 	struct iovec iov;
69099a2dd95SBruce Richardson 	struct msghdr msgh;
69199a2dd95SBruce Richardson 	struct cmsghdr *cmsg;
69299a2dd95SBruce Richardson 	struct sockaddr_un dst;
69399a2dd95SBruce Richardson 	struct mp_msg_internal m;
69499a2dd95SBruce Richardson 	int fd_size = msg->num_fds * sizeof(int);
69599a2dd95SBruce Richardson 	char control[CMSG_SPACE(fd_size)];
69699a2dd95SBruce Richardson 
69799a2dd95SBruce Richardson 	m.type = type;
69899a2dd95SBruce Richardson 	memcpy(&m.msg, msg, sizeof(*msg));
69999a2dd95SBruce Richardson 
70099a2dd95SBruce Richardson 	memset(&dst, 0, sizeof(dst));
70199a2dd95SBruce Richardson 	dst.sun_family = AF_UNIX;
70299a2dd95SBruce Richardson 	strlcpy(dst.sun_path, dst_path, sizeof(dst.sun_path));
70399a2dd95SBruce Richardson 
70499a2dd95SBruce Richardson 	memset(&msgh, 0, sizeof(msgh));
70599a2dd95SBruce Richardson 	memset(control, 0, sizeof(control));
70699a2dd95SBruce Richardson 
70799a2dd95SBruce Richardson 	iov.iov_base = &m;
70899a2dd95SBruce Richardson 	iov.iov_len = sizeof(m) - sizeof(msg->fds);
70999a2dd95SBruce Richardson 
71099a2dd95SBruce Richardson 	msgh.msg_name = &dst;
71199a2dd95SBruce Richardson 	msgh.msg_namelen = sizeof(dst);
71299a2dd95SBruce Richardson 	msgh.msg_iov = &iov;
71399a2dd95SBruce Richardson 	msgh.msg_iovlen = 1;
71499a2dd95SBruce Richardson 	msgh.msg_control = control;
71599a2dd95SBruce Richardson 	msgh.msg_controllen = sizeof(control);
71699a2dd95SBruce Richardson 
71799a2dd95SBruce Richardson 	cmsg = CMSG_FIRSTHDR(&msgh);
71899a2dd95SBruce Richardson 	cmsg->cmsg_len = CMSG_LEN(fd_size);
71999a2dd95SBruce Richardson 	cmsg->cmsg_level = SOL_SOCKET;
72099a2dd95SBruce Richardson 	cmsg->cmsg_type = SCM_RIGHTS;
72199a2dd95SBruce Richardson 	memcpy(CMSG_DATA(cmsg), msg->fds, fd_size);
72299a2dd95SBruce Richardson 
72399a2dd95SBruce Richardson 	do {
72499a2dd95SBruce Richardson 		snd = sendmsg(mp_fd, &msgh, 0);
72599a2dd95SBruce Richardson 	} while (snd < 0 && errno == EINTR);
72699a2dd95SBruce Richardson 
72799a2dd95SBruce Richardson 	if (snd < 0) {
72899a2dd95SBruce Richardson 		rte_errno = errno;
72999a2dd95SBruce Richardson 		/* Check if it caused by peer process exits */
73099a2dd95SBruce Richardson 		if (errno == ECONNREFUSED &&
73199a2dd95SBruce Richardson 				rte_eal_process_type() == RTE_PROC_PRIMARY) {
73299a2dd95SBruce Richardson 			unlink(dst_path);
73399a2dd95SBruce Richardson 			return 0;
73499a2dd95SBruce Richardson 		}
735*ae67895bSDavid Marchand 		EAL_LOG(ERR, "failed to send to (%s) due to %s",
73699a2dd95SBruce Richardson 			dst_path, strerror(errno));
73799a2dd95SBruce Richardson 		return -1;
73899a2dd95SBruce Richardson 	}
73999a2dd95SBruce Richardson 
74099a2dd95SBruce Richardson 	return 1;
74199a2dd95SBruce Richardson }
74299a2dd95SBruce Richardson 
74399a2dd95SBruce Richardson static int
mp_send(struct rte_mp_msg * msg,const char * peer,int type)74499a2dd95SBruce Richardson mp_send(struct rte_mp_msg *msg, const char *peer, int type)
74599a2dd95SBruce Richardson {
74699a2dd95SBruce Richardson 	int dir_fd, ret = 0;
74799a2dd95SBruce Richardson 	DIR *mp_dir;
74899a2dd95SBruce Richardson 	struct dirent *ent;
74999a2dd95SBruce Richardson 
75099a2dd95SBruce Richardson 	if (!peer && (rte_eal_process_type() == RTE_PROC_SECONDARY))
75199a2dd95SBruce Richardson 		peer = eal_mp_socket_path();
75299a2dd95SBruce Richardson 
75399a2dd95SBruce Richardson 	if (peer) {
75499a2dd95SBruce Richardson 		if (send_msg(peer, msg, type) < 0)
75599a2dd95SBruce Richardson 			return -1;
75699a2dd95SBruce Richardson 		else
75799a2dd95SBruce Richardson 			return 0;
75899a2dd95SBruce Richardson 	}
75999a2dd95SBruce Richardson 
76099a2dd95SBruce Richardson 	/* broadcast to all secondary processes */
76199a2dd95SBruce Richardson 	mp_dir = opendir(mp_dir_path);
76299a2dd95SBruce Richardson 	if (!mp_dir) {
763*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Unable to open directory %s",
76499a2dd95SBruce Richardson 				mp_dir_path);
76599a2dd95SBruce Richardson 		rte_errno = errno;
76699a2dd95SBruce Richardson 		return -1;
76799a2dd95SBruce Richardson 	}
76899a2dd95SBruce Richardson 
76999a2dd95SBruce Richardson 	dir_fd = dirfd(mp_dir);
77099a2dd95SBruce Richardson 	/* lock the directory to prevent processes spinning up while we send */
77199a2dd95SBruce Richardson 	if (flock(dir_fd, LOCK_SH)) {
772*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Unable to lock directory %s",
77399a2dd95SBruce Richardson 			mp_dir_path);
77499a2dd95SBruce Richardson 		rte_errno = errno;
77599a2dd95SBruce Richardson 		closedir(mp_dir);
77699a2dd95SBruce Richardson 		return -1;
77799a2dd95SBruce Richardson 	}
77899a2dd95SBruce Richardson 
77999a2dd95SBruce Richardson 	while ((ent = readdir(mp_dir))) {
78099a2dd95SBruce Richardson 		char path[PATH_MAX];
78199a2dd95SBruce Richardson 
78299a2dd95SBruce Richardson 		if (fnmatch(mp_filter, ent->d_name, 0) != 0)
78399a2dd95SBruce Richardson 			continue;
78499a2dd95SBruce Richardson 
78599a2dd95SBruce Richardson 		snprintf(path, sizeof(path), "%s/%s", mp_dir_path,
78699a2dd95SBruce Richardson 			 ent->d_name);
78799a2dd95SBruce Richardson 		if (send_msg(path, msg, type) < 0)
78899a2dd95SBruce Richardson 			ret = -1;
78999a2dd95SBruce Richardson 	}
79099a2dd95SBruce Richardson 	/* unlock the dir */
79199a2dd95SBruce Richardson 	flock(dir_fd, LOCK_UN);
79299a2dd95SBruce Richardson 
79399a2dd95SBruce Richardson 	/* dir_fd automatically closed on closedir */
79499a2dd95SBruce Richardson 	closedir(mp_dir);
79599a2dd95SBruce Richardson 	return ret;
79699a2dd95SBruce Richardson }
79799a2dd95SBruce Richardson 
79899a2dd95SBruce Richardson static int
check_input(const struct rte_mp_msg * msg)79999a2dd95SBruce Richardson check_input(const struct rte_mp_msg *msg)
80099a2dd95SBruce Richardson {
80199a2dd95SBruce Richardson 	if (msg == NULL) {
802*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Msg cannot be NULL");
80399a2dd95SBruce Richardson 		rte_errno = EINVAL;
80499a2dd95SBruce Richardson 		return -1;
80599a2dd95SBruce Richardson 	}
80699a2dd95SBruce Richardson 
80799a2dd95SBruce Richardson 	if (validate_action_name(msg->name) != 0)
80899a2dd95SBruce Richardson 		return -1;
80999a2dd95SBruce Richardson 
81099a2dd95SBruce Richardson 	if (msg->len_param < 0) {
811*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Message data length is negative");
81299a2dd95SBruce Richardson 		rte_errno = EINVAL;
81399a2dd95SBruce Richardson 		return -1;
81499a2dd95SBruce Richardson 	}
81599a2dd95SBruce Richardson 
81699a2dd95SBruce Richardson 	if (msg->num_fds < 0) {
817*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Number of fd's is negative");
81899a2dd95SBruce Richardson 		rte_errno = EINVAL;
81999a2dd95SBruce Richardson 		return -1;
82099a2dd95SBruce Richardson 	}
82199a2dd95SBruce Richardson 
82299a2dd95SBruce Richardson 	if (msg->len_param > RTE_MP_MAX_PARAM_LEN) {
823*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Message data is too long");
82499a2dd95SBruce Richardson 		rte_errno = E2BIG;
82599a2dd95SBruce Richardson 		return -1;
82699a2dd95SBruce Richardson 	}
82799a2dd95SBruce Richardson 
82899a2dd95SBruce Richardson 	if (msg->num_fds > RTE_MP_MAX_FD_NUM) {
829*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Cannot send more than %d FDs",
83099a2dd95SBruce Richardson 			RTE_MP_MAX_FD_NUM);
83199a2dd95SBruce Richardson 		rte_errno = E2BIG;
83299a2dd95SBruce Richardson 		return -1;
83399a2dd95SBruce Richardson 	}
83499a2dd95SBruce Richardson 
83599a2dd95SBruce Richardson 	return 0;
83699a2dd95SBruce Richardson }
83799a2dd95SBruce Richardson 
83899a2dd95SBruce Richardson int
rte_mp_sendmsg(struct rte_mp_msg * msg)83999a2dd95SBruce Richardson rte_mp_sendmsg(struct rte_mp_msg *msg)
84099a2dd95SBruce Richardson {
84199a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
84299a2dd95SBruce Richardson 		eal_get_internal_configuration();
84399a2dd95SBruce Richardson 
84499a2dd95SBruce Richardson 	if (check_input(msg) != 0)
84599a2dd95SBruce Richardson 		return -1;
84699a2dd95SBruce Richardson 
84799a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
848*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "No shared files mode enabled, IPC is disabled");
84999a2dd95SBruce Richardson 		rte_errno = ENOTSUP;
85099a2dd95SBruce Richardson 		return -1;
85199a2dd95SBruce Richardson 	}
85299a2dd95SBruce Richardson 
853*ae67895bSDavid Marchand 	EAL_LOG(DEBUG, "sendmsg: %s", msg->name);
85499a2dd95SBruce Richardson 	return mp_send(msg, NULL, MP_MSG);
85599a2dd95SBruce Richardson }
85699a2dd95SBruce Richardson 
85799a2dd95SBruce Richardson static int
mp_request_async(const char * dst,struct rte_mp_msg * req,struct async_request_param * param,const struct timespec * ts)85899a2dd95SBruce Richardson mp_request_async(const char *dst, struct rte_mp_msg *req,
85999a2dd95SBruce Richardson 		struct async_request_param *param, const struct timespec *ts)
86099a2dd95SBruce Richardson {
86199a2dd95SBruce Richardson 	struct rte_mp_msg *reply_msg;
86299a2dd95SBruce Richardson 	struct pending_request *pending_req, *exist;
86399a2dd95SBruce Richardson 	int ret = -1;
86499a2dd95SBruce Richardson 
86599a2dd95SBruce Richardson 	pending_req = calloc(1, sizeof(*pending_req));
86699a2dd95SBruce Richardson 	reply_msg = calloc(1, sizeof(*reply_msg));
86799a2dd95SBruce Richardson 	if (pending_req == NULL || reply_msg == NULL) {
868*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Could not allocate space for sync request");
86999a2dd95SBruce Richardson 		rte_errno = ENOMEM;
87099a2dd95SBruce Richardson 		ret = -1;
87199a2dd95SBruce Richardson 		goto fail;
87299a2dd95SBruce Richardson 	}
87399a2dd95SBruce Richardson 
87499a2dd95SBruce Richardson 	pending_req->type = REQUEST_TYPE_ASYNC;
87599a2dd95SBruce Richardson 	strlcpy(pending_req->dst, dst, sizeof(pending_req->dst));
87699a2dd95SBruce Richardson 	pending_req->request = req;
87799a2dd95SBruce Richardson 	pending_req->reply = reply_msg;
87899a2dd95SBruce Richardson 	pending_req->async.param = param;
87999a2dd95SBruce Richardson 
88099a2dd95SBruce Richardson 	/* queue already locked by caller */
88199a2dd95SBruce Richardson 
88299a2dd95SBruce Richardson 	exist = find_pending_request(dst, req->name);
88399a2dd95SBruce Richardson 	if (exist) {
884*ae67895bSDavid Marchand 		EAL_LOG(ERR, "A pending request %s:%s", dst, req->name);
88599a2dd95SBruce Richardson 		rte_errno = EEXIST;
88699a2dd95SBruce Richardson 		ret = -1;
88799a2dd95SBruce Richardson 		goto fail;
88899a2dd95SBruce Richardson 	}
88999a2dd95SBruce Richardson 
89099a2dd95SBruce Richardson 	ret = send_msg(dst, req, MP_REQ);
89199a2dd95SBruce Richardson 	if (ret < 0) {
892*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Fail to send request %s:%s",
89399a2dd95SBruce Richardson 			dst, req->name);
89499a2dd95SBruce Richardson 		ret = -1;
89599a2dd95SBruce Richardson 		goto fail;
89699a2dd95SBruce Richardson 	} else if (ret == 0) {
89799a2dd95SBruce Richardson 		ret = 0;
89899a2dd95SBruce Richardson 		goto fail;
89999a2dd95SBruce Richardson 	}
90099a2dd95SBruce Richardson 	param->user_reply.nb_sent++;
90199a2dd95SBruce Richardson 
90299a2dd95SBruce Richardson 	/* if alarm set fails, we simply ignore the reply */
90399a2dd95SBruce Richardson 	if (rte_eal_alarm_set(ts->tv_sec * 1000000 + ts->tv_nsec / 1000,
90499a2dd95SBruce Richardson 			      async_reply_handle, pending_req) < 0) {
905*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Fail to set alarm for request %s:%s",
90699a2dd95SBruce Richardson 			dst, req->name);
90799a2dd95SBruce Richardson 		ret = -1;
90899a2dd95SBruce Richardson 		goto fail;
90999a2dd95SBruce Richardson 	}
91099a2dd95SBruce Richardson 	TAILQ_INSERT_TAIL(&pending_requests.requests, pending_req, next);
91199a2dd95SBruce Richardson 
91299a2dd95SBruce Richardson 	return 0;
91399a2dd95SBruce Richardson fail:
91499a2dd95SBruce Richardson 	free(pending_req);
91599a2dd95SBruce Richardson 	free(reply_msg);
91699a2dd95SBruce Richardson 	return ret;
91799a2dd95SBruce Richardson }
91899a2dd95SBruce Richardson 
91999a2dd95SBruce Richardson static int
mp_request_sync(const char * dst,struct rte_mp_msg * req,struct rte_mp_reply * reply,const struct timespec * ts)92099a2dd95SBruce Richardson mp_request_sync(const char *dst, struct rte_mp_msg *req,
92199a2dd95SBruce Richardson 	       struct rte_mp_reply *reply, const struct timespec *ts)
92299a2dd95SBruce Richardson {
92399a2dd95SBruce Richardson 	int ret;
924cc994d39SChengwen Feng 	pthread_condattr_t attr;
92599a2dd95SBruce Richardson 	struct rte_mp_msg msg, *tmp;
92699a2dd95SBruce Richardson 	struct pending_request pending_req, *exist;
92799a2dd95SBruce Richardson 
92899a2dd95SBruce Richardson 	pending_req.type = REQUEST_TYPE_SYNC;
92999a2dd95SBruce Richardson 	pending_req.reply_received = 0;
93099a2dd95SBruce Richardson 	strlcpy(pending_req.dst, dst, sizeof(pending_req.dst));
93199a2dd95SBruce Richardson 	pending_req.request = req;
93299a2dd95SBruce Richardson 	pending_req.reply = &msg;
933cc994d39SChengwen Feng 	pthread_condattr_init(&attr);
934cc994d39SChengwen Feng 	pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
935cc994d39SChengwen Feng 	pthread_cond_init(&pending_req.sync.cond, &attr);
93699a2dd95SBruce Richardson 
93799a2dd95SBruce Richardson 	exist = find_pending_request(dst, req->name);
93899a2dd95SBruce Richardson 	if (exist) {
939*ae67895bSDavid Marchand 		EAL_LOG(ERR, "A pending request %s:%s", dst, req->name);
94099a2dd95SBruce Richardson 		rte_errno = EEXIST;
94199a2dd95SBruce Richardson 		return -1;
94299a2dd95SBruce Richardson 	}
94399a2dd95SBruce Richardson 
94499a2dd95SBruce Richardson 	ret = send_msg(dst, req, MP_REQ);
94599a2dd95SBruce Richardson 	if (ret < 0) {
946*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Fail to send request %s:%s",
94799a2dd95SBruce Richardson 			dst, req->name);
94899a2dd95SBruce Richardson 		return -1;
94999a2dd95SBruce Richardson 	} else if (ret == 0)
95099a2dd95SBruce Richardson 		return 0;
95199a2dd95SBruce Richardson 
95299a2dd95SBruce Richardson 	TAILQ_INSERT_TAIL(&pending_requests.requests, &pending_req, next);
95399a2dd95SBruce Richardson 
95499a2dd95SBruce Richardson 	reply->nb_sent++;
95599a2dd95SBruce Richardson 
95699a2dd95SBruce Richardson 	do {
95799a2dd95SBruce Richardson 		ret = pthread_cond_timedwait(&pending_req.sync.cond,
95899a2dd95SBruce Richardson 				&pending_requests.lock, ts);
95999a2dd95SBruce Richardson 	} while (ret != 0 && ret != ETIMEDOUT);
96099a2dd95SBruce Richardson 
96199a2dd95SBruce Richardson 	TAILQ_REMOVE(&pending_requests.requests, &pending_req, next);
96299a2dd95SBruce Richardson 
96399a2dd95SBruce Richardson 	if (pending_req.reply_received == 0) {
964*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Fail to recv reply for request %s:%s",
96599a2dd95SBruce Richardson 			dst, req->name);
96699a2dd95SBruce Richardson 		rte_errno = ETIMEDOUT;
96799a2dd95SBruce Richardson 		return -1;
96899a2dd95SBruce Richardson 	}
96999a2dd95SBruce Richardson 	if (pending_req.reply_received == -1) {
970*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "Asked to ignore response");
97199a2dd95SBruce Richardson 		/* not receiving this message is not an error, so decrement
97299a2dd95SBruce Richardson 		 * number of sent messages
97399a2dd95SBruce Richardson 		 */
97499a2dd95SBruce Richardson 		reply->nb_sent--;
97599a2dd95SBruce Richardson 		return 0;
97699a2dd95SBruce Richardson 	}
97799a2dd95SBruce Richardson 
97899a2dd95SBruce Richardson 	tmp = realloc(reply->msgs, sizeof(msg) * (reply->nb_received + 1));
97999a2dd95SBruce Richardson 	if (!tmp) {
980*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Fail to alloc reply for request %s:%s",
98199a2dd95SBruce Richardson 			dst, req->name);
98299a2dd95SBruce Richardson 		rte_errno = ENOMEM;
98399a2dd95SBruce Richardson 		return -1;
98499a2dd95SBruce Richardson 	}
98599a2dd95SBruce Richardson 	memcpy(&tmp[reply->nb_received], &msg, sizeof(msg));
98699a2dd95SBruce Richardson 	reply->msgs = tmp;
98799a2dd95SBruce Richardson 	reply->nb_received++;
98899a2dd95SBruce Richardson 	return 0;
98999a2dd95SBruce Richardson }
99099a2dd95SBruce Richardson 
99199a2dd95SBruce Richardson int
rte_mp_request_sync(struct rte_mp_msg * req,struct rte_mp_reply * reply,const struct timespec * ts)99299a2dd95SBruce Richardson rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply,
99399a2dd95SBruce Richardson 		const struct timespec *ts)
99499a2dd95SBruce Richardson {
99599a2dd95SBruce Richardson 	int dir_fd, ret = -1;
99699a2dd95SBruce Richardson 	DIR *mp_dir;
99799a2dd95SBruce Richardson 	struct dirent *ent;
998cc994d39SChengwen Feng 	struct timespec now, end;
99999a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
100099a2dd95SBruce Richardson 		eal_get_internal_configuration();
100199a2dd95SBruce Richardson 
1002*ae67895bSDavid Marchand 	EAL_LOG(DEBUG, "request: %s", req->name);
100399a2dd95SBruce Richardson 
100499a2dd95SBruce Richardson 	reply->nb_sent = 0;
100599a2dd95SBruce Richardson 	reply->nb_received = 0;
100699a2dd95SBruce Richardson 	reply->msgs = NULL;
100799a2dd95SBruce Richardson 
100899a2dd95SBruce Richardson 	if (check_input(req) != 0)
100999a2dd95SBruce Richardson 		goto end;
101099a2dd95SBruce Richardson 
101199a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
1012*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "No shared files mode enabled, IPC is disabled");
101399a2dd95SBruce Richardson 		rte_errno = ENOTSUP;
101499a2dd95SBruce Richardson 		return -1;
101599a2dd95SBruce Richardson 	}
101699a2dd95SBruce Richardson 
1017cc994d39SChengwen Feng 	if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) {
1018*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Failed to get current time");
101999a2dd95SBruce Richardson 		rte_errno = errno;
102099a2dd95SBruce Richardson 		goto end;
102199a2dd95SBruce Richardson 	}
102299a2dd95SBruce Richardson 
1023cc994d39SChengwen Feng 	end.tv_nsec = (now.tv_nsec + ts->tv_nsec) % 1000000000;
102499a2dd95SBruce Richardson 	end.tv_sec = now.tv_sec + ts->tv_sec +
1025cc994d39SChengwen Feng 			(now.tv_nsec + ts->tv_nsec) / 1000000000;
102699a2dd95SBruce Richardson 
102799a2dd95SBruce Richardson 	/* for secondary process, send request to the primary process only */
102899a2dd95SBruce Richardson 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
102999a2dd95SBruce Richardson 		pthread_mutex_lock(&pending_requests.lock);
103099a2dd95SBruce Richardson 		ret = mp_request_sync(eal_mp_socket_path(), req, reply, &end);
103199a2dd95SBruce Richardson 		pthread_mutex_unlock(&pending_requests.lock);
103299a2dd95SBruce Richardson 		goto end;
103399a2dd95SBruce Richardson 	}
103499a2dd95SBruce Richardson 
103599a2dd95SBruce Richardson 	/* for primary process, broadcast request, and collect reply 1 by 1 */
103699a2dd95SBruce Richardson 	mp_dir = opendir(mp_dir_path);
103799a2dd95SBruce Richardson 	if (!mp_dir) {
1038*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Unable to open directory %s", mp_dir_path);
103999a2dd95SBruce Richardson 		rte_errno = errno;
104099a2dd95SBruce Richardson 		goto end;
104199a2dd95SBruce Richardson 	}
104299a2dd95SBruce Richardson 
104399a2dd95SBruce Richardson 	dir_fd = dirfd(mp_dir);
104499a2dd95SBruce Richardson 	/* lock the directory to prevent processes spinning up while we send */
104599a2dd95SBruce Richardson 	if (flock(dir_fd, LOCK_SH)) {
1046*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Unable to lock directory %s",
104799a2dd95SBruce Richardson 			mp_dir_path);
104899a2dd95SBruce Richardson 		rte_errno = errno;
104999a2dd95SBruce Richardson 		goto close_end;
105099a2dd95SBruce Richardson 	}
105199a2dd95SBruce Richardson 
105299a2dd95SBruce Richardson 	pthread_mutex_lock(&pending_requests.lock);
105399a2dd95SBruce Richardson 	while ((ent = readdir(mp_dir))) {
105499a2dd95SBruce Richardson 		char path[PATH_MAX];
105599a2dd95SBruce Richardson 
105699a2dd95SBruce Richardson 		if (fnmatch(mp_filter, ent->d_name, 0) != 0)
105799a2dd95SBruce Richardson 			continue;
105899a2dd95SBruce Richardson 
105999a2dd95SBruce Richardson 		snprintf(path, sizeof(path), "%s/%s", mp_dir_path,
106099a2dd95SBruce Richardson 			 ent->d_name);
106199a2dd95SBruce Richardson 
106299a2dd95SBruce Richardson 		/* unlocks the mutex while waiting for response,
106399a2dd95SBruce Richardson 		 * locks on receive
106499a2dd95SBruce Richardson 		 */
106599a2dd95SBruce Richardson 		if (mp_request_sync(path, req, reply, &end))
106699a2dd95SBruce Richardson 			goto unlock_end;
106799a2dd95SBruce Richardson 	}
106899a2dd95SBruce Richardson 	ret = 0;
106999a2dd95SBruce Richardson 
107099a2dd95SBruce Richardson unlock_end:
107199a2dd95SBruce Richardson 	pthread_mutex_unlock(&pending_requests.lock);
107299a2dd95SBruce Richardson 	/* unlock the directory */
107399a2dd95SBruce Richardson 	flock(dir_fd, LOCK_UN);
107499a2dd95SBruce Richardson 
107599a2dd95SBruce Richardson close_end:
107699a2dd95SBruce Richardson 	/* dir_fd automatically closed on closedir */
107799a2dd95SBruce Richardson 	closedir(mp_dir);
107899a2dd95SBruce Richardson 
107999a2dd95SBruce Richardson end:
108099a2dd95SBruce Richardson 	if (ret) {
108199a2dd95SBruce Richardson 		free(reply->msgs);
108299a2dd95SBruce Richardson 		reply->nb_received = 0;
108399a2dd95SBruce Richardson 		reply->msgs = NULL;
108499a2dd95SBruce Richardson 	}
108599a2dd95SBruce Richardson 	return ret;
108699a2dd95SBruce Richardson }
108799a2dd95SBruce Richardson 
108899a2dd95SBruce Richardson int
rte_mp_request_async(struct rte_mp_msg * req,const struct timespec * ts,rte_mp_async_reply_t clb)108999a2dd95SBruce Richardson rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,
109099a2dd95SBruce Richardson 		rte_mp_async_reply_t clb)
109199a2dd95SBruce Richardson {
109299a2dd95SBruce Richardson 	struct rte_mp_msg *copy;
109399a2dd95SBruce Richardson 	struct pending_request *dummy;
109499a2dd95SBruce Richardson 	struct async_request_param *param;
109599a2dd95SBruce Richardson 	struct rte_mp_reply *reply;
109699a2dd95SBruce Richardson 	int dir_fd, ret = 0;
109799a2dd95SBruce Richardson 	DIR *mp_dir;
109899a2dd95SBruce Richardson 	struct dirent *ent;
1099cc994d39SChengwen Feng 	struct timespec now;
110099a2dd95SBruce Richardson 	struct timespec *end;
110199a2dd95SBruce Richardson 	bool dummy_used = false;
110299a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
110399a2dd95SBruce Richardson 		eal_get_internal_configuration();
110499a2dd95SBruce Richardson 
1105*ae67895bSDavid Marchand 	EAL_LOG(DEBUG, "request: %s", req->name);
110699a2dd95SBruce Richardson 
110799a2dd95SBruce Richardson 	if (check_input(req) != 0)
110899a2dd95SBruce Richardson 		return -1;
110999a2dd95SBruce Richardson 
111099a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
1111*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "No shared files mode enabled, IPC is disabled");
111299a2dd95SBruce Richardson 		rte_errno = ENOTSUP;
111399a2dd95SBruce Richardson 		return -1;
111499a2dd95SBruce Richardson 	}
111599a2dd95SBruce Richardson 
1116cc994d39SChengwen Feng 	if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) {
1117*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Failed to get current time");
111899a2dd95SBruce Richardson 		rte_errno = errno;
111999a2dd95SBruce Richardson 		return -1;
112099a2dd95SBruce Richardson 	}
112199a2dd95SBruce Richardson 	copy = calloc(1, sizeof(*copy));
112299a2dd95SBruce Richardson 	dummy = calloc(1, sizeof(*dummy));
112399a2dd95SBruce Richardson 	param = calloc(1, sizeof(*param));
112499a2dd95SBruce Richardson 	if (copy == NULL || dummy == NULL || param == NULL) {
1125*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Failed to allocate memory for async reply");
112699a2dd95SBruce Richardson 		rte_errno = ENOMEM;
112799a2dd95SBruce Richardson 		goto fail;
112899a2dd95SBruce Richardson 	}
112999a2dd95SBruce Richardson 
113099a2dd95SBruce Richardson 	/* copy message */
113199a2dd95SBruce Richardson 	memcpy(copy, req, sizeof(*copy));
113299a2dd95SBruce Richardson 
113399a2dd95SBruce Richardson 	param->n_responses_processed = 0;
113499a2dd95SBruce Richardson 	param->clb = clb;
113599a2dd95SBruce Richardson 	end = &param->end;
113699a2dd95SBruce Richardson 	reply = &param->user_reply;
113799a2dd95SBruce Richardson 
1138cc994d39SChengwen Feng 	end->tv_nsec = (now.tv_nsec + ts->tv_nsec) % 1000000000;
113999a2dd95SBruce Richardson 	end->tv_sec = now.tv_sec + ts->tv_sec +
1140cc994d39SChengwen Feng 			(now.tv_nsec + ts->tv_nsec) / 1000000000;
114199a2dd95SBruce Richardson 	reply->nb_sent = 0;
114299a2dd95SBruce Richardson 	reply->nb_received = 0;
114399a2dd95SBruce Richardson 	reply->msgs = NULL;
114499a2dd95SBruce Richardson 
114599a2dd95SBruce Richardson 	/* we have to lock the request queue here, as we will be adding a bunch
114699a2dd95SBruce Richardson 	 * of requests to the queue at once, and some of the replies may arrive
114799a2dd95SBruce Richardson 	 * before we add all of the requests to the queue.
114899a2dd95SBruce Richardson 	 */
114999a2dd95SBruce Richardson 	pthread_mutex_lock(&pending_requests.lock);
115099a2dd95SBruce Richardson 
115199a2dd95SBruce Richardson 	/* we have to ensure that callback gets triggered even if we don't send
115299a2dd95SBruce Richardson 	 * anything, therefore earlier we have allocated a dummy request. fill
115399a2dd95SBruce Richardson 	 * it, and put it on the queue if we don't send any requests.
115499a2dd95SBruce Richardson 	 */
115599a2dd95SBruce Richardson 	dummy->type = REQUEST_TYPE_ASYNC;
115699a2dd95SBruce Richardson 	dummy->request = copy;
115799a2dd95SBruce Richardson 	dummy->reply = NULL;
115899a2dd95SBruce Richardson 	dummy->async.param = param;
115999a2dd95SBruce Richardson 	dummy->reply_received = 1; /* short-circuit the timeout */
116099a2dd95SBruce Richardson 
116199a2dd95SBruce Richardson 	/* for secondary process, send request to the primary process only */
116299a2dd95SBruce Richardson 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
116399a2dd95SBruce Richardson 		ret = mp_request_async(eal_mp_socket_path(), copy, param, ts);
116499a2dd95SBruce Richardson 
116599a2dd95SBruce Richardson 		/* if we didn't send anything, put dummy request on the queue */
116699a2dd95SBruce Richardson 		if (ret == 0 && reply->nb_sent == 0) {
116799a2dd95SBruce Richardson 			TAILQ_INSERT_TAIL(&pending_requests.requests, dummy,
116899a2dd95SBruce Richardson 					next);
116999a2dd95SBruce Richardson 			dummy_used = true;
117099a2dd95SBruce Richardson 		}
117199a2dd95SBruce Richardson 
117299a2dd95SBruce Richardson 		pthread_mutex_unlock(&pending_requests.lock);
117399a2dd95SBruce Richardson 
117499a2dd95SBruce Richardson 		/* if we couldn't send anything, clean up */
117599a2dd95SBruce Richardson 		if (ret != 0)
117699a2dd95SBruce Richardson 			goto fail;
117799a2dd95SBruce Richardson 		return 0;
117899a2dd95SBruce Richardson 	}
117999a2dd95SBruce Richardson 
118099a2dd95SBruce Richardson 	/* for primary process, broadcast request */
118199a2dd95SBruce Richardson 	mp_dir = opendir(mp_dir_path);
118299a2dd95SBruce Richardson 	if (!mp_dir) {
1183*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Unable to open directory %s", mp_dir_path);
118499a2dd95SBruce Richardson 		rte_errno = errno;
118599a2dd95SBruce Richardson 		goto unlock_fail;
118699a2dd95SBruce Richardson 	}
118799a2dd95SBruce Richardson 	dir_fd = dirfd(mp_dir);
118899a2dd95SBruce Richardson 
118999a2dd95SBruce Richardson 	/* lock the directory to prevent processes spinning up while we send */
119099a2dd95SBruce Richardson 	if (flock(dir_fd, LOCK_SH)) {
1191*ae67895bSDavid Marchand 		EAL_LOG(ERR, "Unable to lock directory %s",
119299a2dd95SBruce Richardson 			mp_dir_path);
119399a2dd95SBruce Richardson 		rte_errno = errno;
119499a2dd95SBruce Richardson 		goto closedir_fail;
119599a2dd95SBruce Richardson 	}
119699a2dd95SBruce Richardson 
119799a2dd95SBruce Richardson 	while ((ent = readdir(mp_dir))) {
119899a2dd95SBruce Richardson 		char path[PATH_MAX];
119999a2dd95SBruce Richardson 
120099a2dd95SBruce Richardson 		if (fnmatch(mp_filter, ent->d_name, 0) != 0)
120199a2dd95SBruce Richardson 			continue;
120299a2dd95SBruce Richardson 
120399a2dd95SBruce Richardson 		snprintf(path, sizeof(path), "%s/%s", mp_dir_path,
120499a2dd95SBruce Richardson 			 ent->d_name);
120599a2dd95SBruce Richardson 
120699a2dd95SBruce Richardson 		if (mp_request_async(path, copy, param, ts))
120799a2dd95SBruce Richardson 			ret = -1;
120899a2dd95SBruce Richardson 	}
120999a2dd95SBruce Richardson 	/* if we didn't send anything, put dummy request on the queue */
121099a2dd95SBruce Richardson 	if (ret == 0 && reply->nb_sent == 0) {
121199a2dd95SBruce Richardson 		TAILQ_INSERT_HEAD(&pending_requests.requests, dummy, next);
121299a2dd95SBruce Richardson 		dummy_used = true;
121399a2dd95SBruce Richardson 	}
121499a2dd95SBruce Richardson 
121599a2dd95SBruce Richardson 	/* finally, unlock the queue */
121699a2dd95SBruce Richardson 	pthread_mutex_unlock(&pending_requests.lock);
121799a2dd95SBruce Richardson 
121899a2dd95SBruce Richardson 	/* unlock the directory */
121999a2dd95SBruce Richardson 	flock(dir_fd, LOCK_UN);
122099a2dd95SBruce Richardson 
122199a2dd95SBruce Richardson 	/* dir_fd automatically closed on closedir */
122299a2dd95SBruce Richardson 	closedir(mp_dir);
122399a2dd95SBruce Richardson 
122499a2dd95SBruce Richardson 	/* if dummy was unused, free it */
122599a2dd95SBruce Richardson 	if (!dummy_used)
122699a2dd95SBruce Richardson 		free(dummy);
122799a2dd95SBruce Richardson 
122899a2dd95SBruce Richardson 	return ret;
122999a2dd95SBruce Richardson closedir_fail:
123099a2dd95SBruce Richardson 	closedir(mp_dir);
123199a2dd95SBruce Richardson unlock_fail:
123299a2dd95SBruce Richardson 	pthread_mutex_unlock(&pending_requests.lock);
123399a2dd95SBruce Richardson fail:
123499a2dd95SBruce Richardson 	free(dummy);
123599a2dd95SBruce Richardson 	free(param);
123699a2dd95SBruce Richardson 	free(copy);
123799a2dd95SBruce Richardson 	return -1;
123899a2dd95SBruce Richardson }
123999a2dd95SBruce Richardson 
124099a2dd95SBruce Richardson int
rte_mp_reply(struct rte_mp_msg * msg,const char * peer)124199a2dd95SBruce Richardson rte_mp_reply(struct rte_mp_msg *msg, const char *peer)
124299a2dd95SBruce Richardson {
1243*ae67895bSDavid Marchand 	EAL_LOG(DEBUG, "reply: %s", msg->name);
124499a2dd95SBruce Richardson 	const struct internal_config *internal_conf =
124599a2dd95SBruce Richardson 		eal_get_internal_configuration();
124699a2dd95SBruce Richardson 
124799a2dd95SBruce Richardson 	if (check_input(msg) != 0)
124899a2dd95SBruce Richardson 		return -1;
124999a2dd95SBruce Richardson 
125099a2dd95SBruce Richardson 	if (peer == NULL) {
1251*ae67895bSDavid Marchand 		EAL_LOG(ERR, "peer is not specified");
125299a2dd95SBruce Richardson 		rte_errno = EINVAL;
125399a2dd95SBruce Richardson 		return -1;
125499a2dd95SBruce Richardson 	}
125599a2dd95SBruce Richardson 
125699a2dd95SBruce Richardson 	if (internal_conf->no_shconf) {
1257*ae67895bSDavid Marchand 		EAL_LOG(DEBUG, "No shared files mode enabled, IPC is disabled");
125899a2dd95SBruce Richardson 		return 0;
125999a2dd95SBruce Richardson 	}
126099a2dd95SBruce Richardson 
126199a2dd95SBruce Richardson 	return mp_send(msg, peer, MP_REP);
126299a2dd95SBruce Richardson }
126399a2dd95SBruce Richardson 
126499a2dd95SBruce Richardson /* Internally, the status of the mp feature is represented as a three-state:
126599a2dd95SBruce Richardson  * - "unknown" as long as no secondary process attached to a primary process
126699a2dd95SBruce Richardson  *   and there was no call to rte_mp_disable yet,
126799a2dd95SBruce Richardson  * - "enabled" as soon as a secondary process attaches to a primary process,
126899a2dd95SBruce Richardson  * - "disabled" when a primary process successfully called rte_mp_disable,
126999a2dd95SBruce Richardson  */
127099a2dd95SBruce Richardson enum mp_status {
127199a2dd95SBruce Richardson 	MP_STATUS_UNKNOWN,
127299a2dd95SBruce Richardson 	MP_STATUS_DISABLED,
127399a2dd95SBruce Richardson 	MP_STATUS_ENABLED,
127499a2dd95SBruce Richardson };
127599a2dd95SBruce Richardson 
127699a2dd95SBruce Richardson static bool
set_mp_status(enum mp_status status)127799a2dd95SBruce Richardson set_mp_status(enum mp_status status)
127899a2dd95SBruce Richardson {
127999a2dd95SBruce Richardson 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
128099a2dd95SBruce Richardson 	uint8_t expected;
128199a2dd95SBruce Richardson 	uint8_t desired;
128299a2dd95SBruce Richardson 
128399a2dd95SBruce Richardson 	expected = MP_STATUS_UNKNOWN;
128499a2dd95SBruce Richardson 	desired = status;
12852a7a42a5STyler Retzlaff 	if (rte_atomic_compare_exchange_strong_explicit(&mcfg->mp_status, &expected, desired,
12862a7a42a5STyler Retzlaff 			rte_memory_order_relaxed, rte_memory_order_relaxed))
128799a2dd95SBruce Richardson 		return true;
128899a2dd95SBruce Richardson 
12892a7a42a5STyler Retzlaff 	return rte_atomic_load_explicit(&mcfg->mp_status, rte_memory_order_relaxed) == desired;
129099a2dd95SBruce Richardson }
129199a2dd95SBruce Richardson 
129299a2dd95SBruce Richardson bool
rte_mp_disable(void)129399a2dd95SBruce Richardson rte_mp_disable(void)
129499a2dd95SBruce Richardson {
129599a2dd95SBruce Richardson 	return set_mp_status(MP_STATUS_DISABLED);
129699a2dd95SBruce Richardson }
129799a2dd95SBruce Richardson 
129899a2dd95SBruce Richardson bool
__rte_mp_enable(void)129999a2dd95SBruce Richardson __rte_mp_enable(void)
130099a2dd95SBruce Richardson {
130199a2dd95SBruce Richardson 	return set_mp_status(MP_STATUS_ENABLED);
130299a2dd95SBruce Richardson }
1303