]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ofed/management/opensm/libvendor/osm_pkt_randomizer.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ofed / management / opensm / libvendor / osm_pkt_randomizer.c
1 /*
2  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  */
35
36 /*
37  * Abstract:
38  *    Implementation of osm_pkt_randomizer_t.
39  *
40  */
41
42 #if HAVE_CONFIG_H
43 #  include <config.h>
44 #endif                          /* HAVE_CONFIG_H */
45
46 #include <vendor/osm_pkt_randomizer.h>
47 #include <stdlib.h>
48 #include <string.h>
49
50 #ifndef WIN32
51 #include <sys/time.h>
52 #include <unistd.h>
53 #endif
54
55 /**********************************************************************
56  * Return TRUE if the path is in a fault path, and FALSE otherwise.
57  * By in a fault path the meaning is that there is a path in the fault
58  * paths that the given path includes it.
59  * E.g: if there is a fault path: 0,1,4
60  * For the given path: 0,1,4,7 the return value will be TRUE, also for
61  * the given path: 0,1,4 the return value will be TRUE, but for
62  * the given paths: 0,1 or 0,3,1,4 - the return value will be FALSE.
63  **********************************************************************/
64 boolean_t
65 __osm_pkt_randomizer_is_path_in_fault_paths(IN osm_log_t * p_log,
66                                             IN osm_dr_path_t * p_dr_path,
67                                             IN osm_pkt_randomizer_t *
68                                             p_pkt_rand)
69 {
70         boolean_t res = FALSE, found_path;
71         osm_dr_path_t *p_found_dr_path;
72         uint8_t ind1, ind2;
73
74         OSM_LOG_ENTER(p_log);
75
76         for (ind1 = 0; ind1 < p_pkt_rand->num_paths_initialized; ind1++) {
77                 found_path = TRUE;
78                 p_found_dr_path = &(p_pkt_rand->fault_dr_paths[ind1]);
79                 /* if the hop count of the found path is greater than the
80                    hop count of the input path - then it is not part of it.
81                    Check the next path. */
82                 if (p_found_dr_path->hop_count > p_dr_path->hop_count)
83                         continue;
84
85                 /* go over all the ports in the found path and see if they match
86                    the ports in the input path */
87                 for (ind2 = 0; ind2 <= p_found_dr_path->hop_count; ind2++)
88                         if (p_found_dr_path->path[ind2] !=
89                             p_dr_path->path[ind2])
90                                 found_path = FALSE;
91
92                 /* If found_path is TRUE  then there is a full match of the path */
93                 if (found_path == TRUE) {
94                         OSM_LOG(p_log, OSM_LOG_VERBOSE,
95                                 "Given path is in a fault path\n");
96                         res = TRUE;
97                         break;
98                 }
99         }
100
101         OSM_LOG_EXIT(p_log);
102         return res;
103 }
104
105 /**********************************************************************
106  * For a given dr_path - return TRUE if the path should be dropped,
107  * return FALSE otherwise.
108  * The check uses random criteria in order to determine whether or not
109  * the path should be dropped.
110  * First - if not all paths are initialized, it randomally chooses if
111  * to use this path as a fault path or not.
112  * Second - if the path is in the fault paths (meaning - it is equal
113  * to or includes one of the fault paths) - then it randomally chooses
114  * if to drop it or not.
115  **********************************************************************/
116 boolean_t
117 __osm_pkt_randomizer_process_path(IN osm_log_t * p_log,
118                                   IN osm_pkt_randomizer_t * p_pkt_rand,
119                                   IN osm_dr_path_t * p_dr_path)
120 {
121         boolean_t res = FALSE;
122         static boolean_t rand_value_init = FALSE;
123         static int rand_value;
124         boolean_t in_fault_paths;
125         uint8_t i;
126         char buf[BUF_SIZE];
127         char line[BUF_SIZE];
128
129         OSM_LOG_ENTER(p_log);
130
131         if (rand_value_init == FALSE) {
132                 int seed;
133 #ifdef WIN32
134                 SYSTEMTIME st;
135 #else
136                 struct timeval tv;
137                 struct timezone tz;
138 #endif                          /*  WIN32 */
139
140                 /* initiate the rand_value according to timeofday */
141                 rand_value_init = TRUE;
142
143 #ifdef WIN32
144                 GetLocalTime(&st);
145                 seed = st.wMilliseconds;
146 #else
147                 gettimeofday(&tv, &tz);
148                 seed = tv.tv_usec;
149 #endif                          /*  WIN32 */
150
151                 srand(seed);
152         }
153
154         /* If the hop_count is 1 - then this is a mad down to our local port - don't drop it */
155         if (p_dr_path->hop_count <= 1)
156                 goto Exit;
157
158         rand_value = rand();
159
160         sprintf(buf, "Path: ");
161         /* update the dr_path into the buf */
162         for (i = 0; i <= p_dr_path->hop_count; i++) {
163                 sprintf(line, "[%X]", p_dr_path->path[i]);
164                 strcat(buf, line);
165         }
166
167         /* Check if the path given is in one of the fault paths */
168         in_fault_paths =
169             __osm_pkt_randomizer_is_path_in_fault_paths(p_log, p_dr_path,
170                                                         p_pkt_rand);
171
172         /* Check if all paths are initialized */
173         if (p_pkt_rand->num_paths_initialized <
174             p_pkt_rand->osm_pkt_num_unstable_links) {
175                 /* Not all packets are initialized. */
176                 if (in_fault_paths == FALSE) {
177                         /* the path is not in the false paths. Check using the rand value
178                            if to update it there or not. */
179                         if (rand_value %
180                             (p_pkt_rand->osm_pkt_unstable_link_rate) == 0) {
181                                 OSM_LOG(p_log, OSM_LOG_VERBOSE,
182                                         "%s added to the fault_dr_paths list\n"
183                                         "\t\t\t rand_value:%u, unstable_link_rate:%u \n",
184                                         buf, rand_value,
185                                         p_pkt_rand->osm_pkt_unstable_link_rate);
186
187                                 /* update the path in the fault paths */
188                                 memcpy(&
189                                        (p_pkt_rand->
190                                         fault_dr_paths[p_pkt_rand->
191                                                        num_paths_initialized]),
192                                        p_dr_path, sizeof(osm_dr_path_t));
193                                 p_pkt_rand->num_paths_initialized++;
194                                 in_fault_paths = TRUE;
195                         }
196                 }
197         }
198
199         if (in_fault_paths == FALSE) {
200                 /* If in_fault_paths is FALSE - just ignore the path */
201                 OSM_LOG(p_log, OSM_LOG_VERBOSE, "%s not in fault paths\n", buf);
202                 goto Exit;
203         }
204
205         /* The path is in the fault paths. Need to choose (randomally if to drop it
206            or not. */
207         rand_value = rand();
208
209         if (rand_value % (p_pkt_rand->osm_pkt_drop_rate) == 0) {
210                 /* drop the current packet */
211                 res = TRUE;
212                 OSM_LOG(p_log, OSM_LOG_VERBOSE, "Dropping path:%s\n", buf);
213         }
214
215 Exit:
216         OSM_LOG_EXIT(p_log);
217         return res;
218 }
219
220 /**********************************************************************
221  **********************************************************************/
222 boolean_t
223 osm_pkt_randomizer_mad_drop(IN osm_log_t * p_log,
224                             IN osm_pkt_randomizer_t * p_pkt_randomizer,
225                             IN const ib_mad_t * p_mad)
226 {
227         const ib_smp_t *p_smp;
228         boolean_t res = FALSE;
229         osm_dr_path_t dr_path;
230
231         OSM_LOG_ENTER(p_log);
232
233         p_smp = (ib_smp_t *) p_mad;
234
235         if (p_smp->mgmt_class != IB_MCLASS_SUBN_DIR)
236                 /* This is a lid route mad. Don't drop it */
237                 goto Exit;
238
239         osm_dr_path_init(&dr_path, 0,   /* The h_bind is not really important for us to save */
240                          p_smp->hop_count, p_smp->initial_path);
241
242         if (__osm_pkt_randomizer_process_path
243             (p_log, p_pkt_randomizer, &dr_path)) {
244                 /* the mad should be dropped o */
245                 OSM_LOG(p_log, OSM_LOG_VERBOSE,
246                         "mad TID: 0x%" PRIx64 " is being dropped\n",
247                         cl_ntoh64(p_smp->trans_id));
248                 res = TRUE;
249         }
250
251 Exit:
252         OSM_LOG_EXIT(p_log);
253         return res;
254 }
255
256 /**********************************************************************
257  **********************************************************************/
258 ib_api_status_t
259 osm_pkt_randomizer_init(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer,
260                         IN osm_log_t * p_log)
261 {
262         uint8_t tmp;
263         ib_api_status_t res = IB_SUCCESS;
264
265         OSM_LOG_ENTER(p_log);
266
267         *pp_pkt_randomizer = malloc(sizeof(osm_pkt_randomizer_t));
268         if (*pp_pkt_randomizer == NULL) {
269                 res = IB_INSUFFICIENT_MEMORY;
270                 goto Exit;
271         }
272         memset(*pp_pkt_randomizer, 0, sizeof(osm_pkt_randomizer_t));
273         (*pp_pkt_randomizer)->num_paths_initialized = 0;
274
275         tmp = atol(getenv("OSM_PKT_DROP_RATE"));
276         (*pp_pkt_randomizer)->osm_pkt_drop_rate = tmp;
277
278         if (getenv("OSM_PKT_NUM_UNSTABLE_LINKS") != NULL
279             && (tmp = atol(getenv("OSM_PKT_NUM_UNSTABLE_LINKS"))) > 0)
280                 (*pp_pkt_randomizer)->osm_pkt_num_unstable_links = tmp;
281         else
282                 (*pp_pkt_randomizer)->osm_pkt_num_unstable_links = 1;
283
284         if (getenv("OSM_PKT_UNSTABLE_LINK_RATE") != NULL
285             && (tmp = atol(getenv("OSM_PKT_UNSTABLE_LINK_RATE"))) > 0)
286                 (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = tmp;
287         else
288                 (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = 20;
289
290         OSM_LOG(p_log, OSM_LOG_VERBOSE, "Using OSM_PKT_DROP_RATE=%u \n"
291                 "\t\t\t\t OSM_PKT_NUM_UNSTABLE_LINKS=%u \n"
292                 "\t\t\t\t OSM_PKT_UNSTABLE_LINK_RATE=%u \n",
293                 (*pp_pkt_randomizer)->osm_pkt_drop_rate,
294                 (*pp_pkt_randomizer)->osm_pkt_num_unstable_links,
295                 (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate);
296
297         /* allocate the fault_dr_paths variable */
298         /* It is the number of the paths that will be saved as fault = osm_pkt_num_unstable_links */
299         (*pp_pkt_randomizer)->fault_dr_paths = malloc(sizeof(osm_dr_path_t) *
300                                                       (*pp_pkt_randomizer)->
301                                                       osm_pkt_num_unstable_links);
302         if ((*pp_pkt_randomizer)->fault_dr_paths == NULL) {
303                 res = IB_INSUFFICIENT_MEMORY;
304                 goto Exit;
305         }
306
307         memset((*pp_pkt_randomizer)->fault_dr_paths, 0,
308                sizeof(osm_dr_path_t) *
309                (*pp_pkt_randomizer)->osm_pkt_num_unstable_links);
310
311 Exit:
312         OSM_LOG_EXIT(p_log);
313         return (res);
314 }
315
316 /**********************************************************************
317  **********************************************************************/
318 void
319 osm_pkt_randomizer_destroy(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer,
320                            IN osm_log_t * p_log)
321 {
322         OSM_LOG_ENTER(p_log);
323
324         if (*pp_pkt_randomizer != NULL) {
325                 free((*pp_pkt_randomizer)->fault_dr_paths);
326                 free(*pp_pkt_randomizer);
327         }
328         OSM_LOG_EXIT(p_log);
329 }