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 **********************************************************************/ 64boolean_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 **********************************************************************/ 116boolean_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 215Exit: 216 OSM_LOG_EXIT(p_log); 217 return res; 218} 219 220/********************************************************************** 221 **********************************************************************/ 222boolean_t 223osm_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 251Exit: 252 OSM_LOG_EXIT(p_log); 253 return res; 254} 255 256/********************************************************************** 257 **********************************************************************/ 258ib_api_status_t 259osm_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 311Exit: 312 OSM_LOG_EXIT(p_log); 313 return (res); 314} 315 316/********************************************************************** 317 **********************************************************************/ 318void 319osm_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} 330