1 /*
2  * Copyright (c) 2015-2016 Cray Inc.  All rights reserved.
3  * Copyright (c) 2015-2017 Los Alamos National Security, LLC. All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  */
33 
34 #ifndef _GNIX_DATAGRAM_H_
35 #define _GNIX_DATAGRAM_H_
36 
37 #include "gnix.h"
38 
39 /*
40  * GNI datagram related structs and defines.
41  * The GNI_EpPostDataWId, etc. are used to manage
42  * connecting VC's for the FI_EP_RDM endpoint
43  * type.
44  *
45  * There are two types of datagrams used by the
46  * gni provider: bound (bnd) datagrams and wildcard (wc)
47  * datagrams.
48  *
49  * Bound datagrams are those that are bound to a particular
50  * target nic address by means of the GNI_EpBind function
51  * When a bound datagram is submitted to the datagram system via
52  * a GNI_EpPostDataWId, kgni forwards the datagram to
53  * the target node/cdm_id. Note that once a datagram exchange
54  * has been completed, the datagram can be unbound using
55  * the GNI_EpUnbind, and subsequently reused to target a different
56  * gni nic address/cdm_id.
57  *
58  * Wildcard datagrams have semantics similar to listening
59  * sockets.  When a wildcard datagram is submitted to the
60  * datagram system, kgni adds the datagram to the list of
61  * datagrams to match for the given gni nic/cdm_id.  When an
62  * incoming bound datagram matches the wildcard, the datagram
63  * exchange is completed.
64  */
65 
66 /**
67  * Set of attributes that can be used as an argument to gnix_dgram_hndl_alloc
68  *
69  * @var timeout_needed       pointer to a function which returns true
70  *                           if a timeout is needed in the call to
71  *                           GNI_EpPostdataWaitById to insure progress
72  * @var timeout_progress     pointer to a function should be invoked
73  *                           by the datagram engine to progress
74  *                           the state of the consumer of the datagram
75  *                           functionality.
76  * @var timeout_data         pointer to data supplied as the argument to
77  *                           the timeout_needed and timeout_progress methods
78  * @var timeout              the timeout value in milliseconds to be
79  *                           supplied to GNI_EpPostdataWaitById if
80  *                           timeout_needed returns to true
81  */
82 struct gnix_dgram_hndl_attr {
83 	bool (*timeout_needed)(void *);
84 	void (*timeout_progress)(void *);
85 	void *timeout_data;
86 	uint32_t timeout;
87 };
88 
89 /**
90  * Datagram allocator struct
91  *
92  * @var cm_nic               pointer to a previously allocated cm_nic with
93  *                           which this datagram is associated
94  * @var bnd_dgram_free_list  head of free list for bound datagrams
95  * @var bnd_dgram_active_list  head of active list for bound datagrams
96  * @var wc_dgram_free_list   head of free list of wildcard datagrams
97  * @var wc_dgram_active_list head of active list of wildcard datagrams
98  * @var dgram_base           starting address of memory block from
99  *                           which datagram structures are allocated
100  * @var timeout_needed       In the case of FI_PROGRESS_AUTO, invoke this
101  *                           method prior to call to GNI_EpPostDataWaitById
102  *                           to check if we need to timeout in order to
103  *                           progress datagrams which had been stalled
104  *                           due to GNI_RC_ERROR_RESOURCE.
105  * @var lock                 lock to protect dgram lists
106  * @var progress_thread      pthread id of progress thread for this
107  *                           datagram allocator
108  * @var n_dgrams             number of bound datagrams managed by the
109  *                           datagram allocator
110  * @var n_wc_dgrams          number of wildcard datagrams managed by
111  *                           the datagram allocator
112  * @var timeout              time in milliseconds to wait for datagram to
113  *                           complete. By default set to -1 (infinite timeout),
114  *                           but can be set to handle cases where a timeout
115  *                           is required when using FI_PROGRESS_AUTO for
116  *                           control progress.
117  */
118 struct gnix_dgram_hndl {
119 	struct gnix_cm_nic *cm_nic;
120 	struct dlist_entry bnd_dgram_free_list;
121 	struct dlist_entry bnd_dgram_active_list;
122 	struct dlist_entry wc_dgram_free_list;
123 	struct dlist_entry wc_dgram_active_list;
124 	struct gnix_datagram *dgram_base;
125 	bool (*timeout_needed)(void *);
126 	void (*timeout_progress)(void *);
127 	void *timeout_data;
128 	fastlock_t lock;
129 	pthread_t progress_thread;
130 	int n_dgrams;
131 	int n_wc_dgrams;
132 	uint32_t timeout;
133 };
134 
135 enum gnix_dgram_type {
136 	GNIX_DGRAM_WC = 100,
137 	GNIX_DGRAM_BND
138 };
139 
140 enum gnix_dgram_state {
141 	GNIX_DGRAM_STATE_FREE,
142 	GNIX_DGRAM_STATE_ACTIVE
143 };
144 
145 enum gnix_dgram_buf {
146 	GNIX_DGRAM_IN_BUF,
147 	GNIX_DGRAM_OUT_BUF
148 };
149 
150 enum gnix_dgram_poll_type {
151 	GNIX_DGRAM_NOBLOCK,
152 	GNIX_DGRAM_BLOCK
153 };
154 
155 /**
156  * @brief GNI datagram structure
157  *
158  * @var list                 list element for managing datagrams in llists
159  * @var free_list_head       pointer to free list head from which
160  *                           this datagram is allocated
161  * @var gni_ep               GNI ep used for posting this datagram to GNI
162  * @var nic                  gnix connection management (cm) nic with which
163  *                           this datagram is associated
164  * @var target_addr          target address to which this datagram is to be
165  *                           delivered which posted to GNI (applicable only
166  *                           for bound datagrams)
167  * @var state                state of the datagram (see enum gnix_dgram_state)
168  * @var type                 datagram type (bound or wildcard)
169  * @var d_hndl               pointer to datagram handle this datagram is
170  *                           associated
171  * @var pre_post_clbk_fn     Call back function to be called prior to
172  *                           to the call to GNI_EpPostDataWId. This callback
173  *                           is invoked while the lock is held on the cm nic.
174  * @var post_post_clbk_fn    Call back function to be called following
175  *                           a call to GNI_EpPostDataWId. This callback
176  *                           is invoked while the lock is held on the cm nic.
177  * @var callback_fn          Call back function to be called following
178  *                           a call GNI_EpPostDataTestById and a datagram
179  *                           is returned in any of the following GNI
180  *                           post state states: GNI_POST_TIMEOUT,
181  *                           GNI_POST_TERMINATED, GNI_POST_ERROR, or
182  *                           GNI_POST_COMPLETED.  The cm nic lock is
183  *                           not held when this callback is invoked.
184  * @var r_index_in_buf       Internal index for tracking where to unstart
185  *                           a unpack request on the GNIX_DGRAM_IN_BUF buffer
186  *                           of the datagram.
187  * @var w_index_in_buf       Internal index for tracking where to unstart
188  *                           a pack request on the GNIX_DGRAM_IN_BUF buffer
189  *                           of the datagram.
190  * @var r_index_out_buf      Internal index for tracking where to unstart
191  *                           a unpack request on the GNIX_DGRAM_OUT_BUF buffer
192  *                           of the datagram.
193  * @var w_index_out_buf      Internal index for tracking where to unstart
194  *                           a pack request on the GNIX_DGRAM_OUT_BUF buffer
195  *                           of the datagram.
196  * @var cache                Pointer that can be used by datagram user to track
197  *                           data associated with the datagram transaction.
198  * @var dgram_in_buf         Internal buffer used for the IN data to be
199  *                           posted to the GNI.
200  * @var dgram_out_buf        Internal buffer used for the OUT data to be
201  *                           posted to the GNI.
202  */
203 struct gnix_datagram {
204 	struct dlist_entry      list;
205 	struct dlist_entry       *free_list_head;
206 	gni_ep_handle_t         gni_ep;
207 	struct gnix_cm_nic      *cm_nic;
208 	struct gnix_address     target_addr;
209 	enum gnix_dgram_state   state;
210 	enum gnix_dgram_type    type;
211 	struct gnix_dgram_hndl  *d_hndl;
212 	int  (*pre_post_clbk_fn)(struct gnix_datagram *,
213 				 int *);
214 	int  (*post_post_clbk_fn)(struct gnix_datagram *,
215 				  gni_return_t);
216 	int  (*callback_fn)(struct gnix_datagram *,
217 			    struct gnix_address,
218 			    gni_post_state_t);
219 	int r_index_in_buf;
220 	int w_index_in_buf;
221 	int r_index_out_buf;
222 	int w_index_out_buf;
223 	void *cache;
224 	char dgram_in_buf[GNI_DATAGRAM_MAXSIZE];
225 	char dgram_out_buf[GNI_DATAGRAM_MAXSIZE];
226 };
227 
228 /*
229  * prototypes for gni datagram internal functions
230  */
231 
232 /**
233  * @brief Allocates a handle to a datagram allocator instance
234  *
235  * @param[in]  cm_nic     pointer to previously allocated gnix_cm_nic object
236  * @param[in]  attr       optional pointer to a gnix_dgram_hndl_attr
237  *                        structure
238  * @param[in]  progress   progress model to be used for this cm_nic
239  *                        (see fi_domain man page)
240  * @param[out] handl_ptr  location in which the address of the allocated
241  *                        datagram allocator handle is to be returned
242  * @return FI_SUCCESS     Upon successfully creating a datagram allocator.
243  * @return -FI_ENOMEM     Insufficient memory to create datagram allocator
244  * @return -FI_EINVAL     Upon getting an invalid fabric or cm_nic handle
245  * @return -FI_EAGAIN     In the case of FI_PROGRESS_AUTO, system lacked
246  *                        resources to spawn a progress thread.
247  */
248 int _gnix_dgram_hndl_alloc(struct gnix_cm_nic *cm_nic,
249 			   enum fi_progress progress,
250 			   const struct gnix_dgram_hndl_attr *attr,
251 			   struct gnix_dgram_hndl **hndl_ptr);
252 
253 /**
254  * @brief Frees a handle to a datagram allocator and associated internal
255  *        structures
256  *
257  * @param[in]  hndl       pointer to previously allocated datagram allocator
258  *                        instance
259  * @return FI_SUCCESS     Upon successfully freeing the datagram allocator
260  *                        handle and associated internal structures
261  * @return -FI_EINVAL     Invalid handle to a datagram allocator was supplied
262  *                        as input
263  */
264 int _gnix_dgram_hndl_free(struct gnix_dgram_hndl *hndl);
265 
266 /**
267  * @brief  Allocates a datagram
268  *
269  * @param[in]  hndl       pointer to previously allocated datagram allocator
270  *                        instance
271  * @param[in] type        datagram type - wildcard or bound
272  * @param[out] d_ptr      location in which the address of the allocated
273  *                        datagram is to be returned
274  * @return FI_SUCCESS     Upon successfully allocating a datagram
275  * @return -FI_EAGAIN     Temporarily insufficient resources to allocate
276  *                        a datagram.  The associated cm_nic needs to be
277  *                        progressed.
278  */
279 int _gnix_dgram_alloc(struct gnix_dgram_hndl *hndl,
280 			enum gnix_dgram_type type,
281 			struct gnix_datagram **d_ptr);
282 
283 /**
284  * @brief  Frees a datagram
285  *
286  * @param[in]  d          pointer to previously allocated datagram
287  *                        datagram is to be returned
288  * @return FI_SUCCESS     Upon successfully freeing a datagram
289  * @return -FI_EINVAL     Invalid argument was supplied
290  * @return -FI_EOPBADSTAT Datagram is currently in an internal state where
291  *                        it cannot be freed
292  */
293 int _gnix_dgram_free(struct gnix_datagram *d);
294 
295 /**
296  * @brief  Post a wildcard datagram to the GNI datagram state engine
297  *
298  * @param[in]  d          pointer to previously allocated datagram
299  * @return FI_SUCCESS     Upon successfully posting a wildcard datagram
300  * @return -FI_EINVAL     Invalid argument was supplied
301  * @return -FI_ENOMEM     Insufficient memory to post datagram
302  * @return -FI_EMSGSIZE   Payload for datagram exceeds internally
303  *                        supported size (see GNI_DATAGRAM_MAXSIZE in
304  *                        gni_pub.h)
305  */
306 int _gnix_dgram_wc_post(struct gnix_datagram *d);
307 
308 /**
309  * @brief  Post a bound datagram to the GNI datagram state engine
310  *
311  * @param[in]  d          pointer to previously allocated datagram
312  * @return FI_SUCCESS     Upon successfully posting a wildcard datagram
313  * @return -FI_EINVAL     Invalid argument was supplied
314  * @return -FI_ENOMEM     Insufficient memory to post datagram
315  * @return -FI_BUSY       Only one outstanding datagram to a given
316  8                        target address is allowed
317  * @return -FI_EMSGSIZE   Payload for datagram exceeds internally
318  *                        supported size (see GNI_DATAGRAM_MAXSIZE in
319  *                        gni_pub.h)
320  */
321 int _gnix_dgram_bnd_post(struct gnix_datagram *d);
322 
323 /**
324  * @brief   Pack the buffer of a previously allocated datagram
325  *          with application data
326  * @param[in] d           pointer to previously allocated datagram
327  * @param[in] gnix_dgram_buf which buffer into which to pack data
328  * @param[in] data        pointer to data to be packed
329  * @param[in] nbytes      number of bytes to pack
330  * @return  (> 0)         number of bytes packed
331  * @return -FI_EINVAL     Invalid argument was supplied
332  * @return -FI_ENOSPC     Insufficient space for data
333  */
334 ssize_t _gnix_dgram_pack_buf(struct gnix_datagram *d, enum gnix_dgram_buf,
335 			 void *data, uint32_t nbytes);
336 
337 /**
338  * @brief   Unpack the buffer of a previously allocated datagram
339  *          with application data
340  * @param[in] d           pointer to previously allocated datagram
341  * @param[in] gnix_dgram_buf which buffer from which to unpack data
342  * @param[in] data        address into which the data is to be unpacked
343  * @param[in] nbytes      number of bytes to unpacked
344  * @return  (> 0)         number of bytes unpacked
345  */
346 ssize_t _gnix_dgram_unpack_buf(struct gnix_datagram *d, enum gnix_dgram_buf,
347 			   void *data, uint32_t nbytes);
348 
349 /**
350  * @brief   rewind the internal pointers to datagram buffers to
351  *          beginning of the internal buffers
352  * @param[in] d           pointer to previously allocated datagram
353  * @param[in] gnix_dgram_buf which buffer to rewind
354  * @param[in] data        address into which the data is to be unpacked
355  * @param[in] nbytes      number of bytes to unpacked
356  * @return FI_SUCCESS     Upon successfully rewinding internal buffer
357  *                        pointers
358  */
359 int _gnix_dgram_rewind_buf(struct gnix_datagram *d, enum gnix_dgram_buf);
360 
361 /**
362  * @brief   poll datagram handle to progress the underlying cm_nic's
363  *          progress engine
364  * @param[in] hndl_ptr    handle to a previously allocated datagram
365  *                        allocator
366  * @param[in] type        progress type (blocking or non-blocking)
367  * @return FI_SUCCESS     Upon successfully progressing the state
368  *                        engine
369  */
370 int _gnix_dgram_poll(struct gnix_dgram_hndl *hndl_ptr,
371 			enum gnix_dgram_poll_type type);
372 
373 
374 #endif /* _GNIX_DATAGRAM_H_ */
375