1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff * 34219820Sjeff */ 35219820Sjeff 36219820Sjeff/* 37219820Sjeff * Abstract: 38219820Sjeff * Implementation of osm_pkt_randomizer_t. 39219820Sjeff * 40219820Sjeff */ 41219820Sjeff 42219820Sjeff#if HAVE_CONFIG_H 43219820Sjeff# include <config.h> 44219820Sjeff#endif /* HAVE_CONFIG_H */ 45219820Sjeff 46219820Sjeff#include <vendor/osm_pkt_randomizer.h> 47219820Sjeff#include <stdlib.h> 48219820Sjeff#include <string.h> 49219820Sjeff 50219820Sjeff#ifndef WIN32 51219820Sjeff#include <sys/time.h> 52219820Sjeff#include <unistd.h> 53219820Sjeff#endif 54219820Sjeff 55219820Sjeff/********************************************************************** 56219820Sjeff * Return TRUE if the path is in a fault path, and FALSE otherwise. 57219820Sjeff * By in a fault path the meaning is that there is a path in the fault 58219820Sjeff * paths that the given path includes it. 59219820Sjeff * E.g: if there is a fault path: 0,1,4 60219820Sjeff * For the given path: 0,1,4,7 the return value will be TRUE, also for 61219820Sjeff * the given path: 0,1,4 the return value will be TRUE, but for 62219820Sjeff * the given paths: 0,1 or 0,3,1,4 - the return value will be FALSE. 63219820Sjeff **********************************************************************/ 64219820Sjeffboolean_t 65219820Sjeff__osm_pkt_randomizer_is_path_in_fault_paths(IN osm_log_t * p_log, 66219820Sjeff IN osm_dr_path_t * p_dr_path, 67219820Sjeff IN osm_pkt_randomizer_t * 68219820Sjeff p_pkt_rand) 69219820Sjeff{ 70219820Sjeff boolean_t res = FALSE, found_path; 71219820Sjeff osm_dr_path_t *p_found_dr_path; 72219820Sjeff uint8_t ind1, ind2; 73219820Sjeff 74219820Sjeff OSM_LOG_ENTER(p_log); 75219820Sjeff 76219820Sjeff for (ind1 = 0; ind1 < p_pkt_rand->num_paths_initialized; ind1++) { 77219820Sjeff found_path = TRUE; 78219820Sjeff p_found_dr_path = &(p_pkt_rand->fault_dr_paths[ind1]); 79219820Sjeff /* if the hop count of the found path is greater than the 80219820Sjeff hop count of the input path - then it is not part of it. 81219820Sjeff Check the next path. */ 82219820Sjeff if (p_found_dr_path->hop_count > p_dr_path->hop_count) 83219820Sjeff continue; 84219820Sjeff 85219820Sjeff /* go over all the ports in the found path and see if they match 86219820Sjeff the ports in the input path */ 87219820Sjeff for (ind2 = 0; ind2 <= p_found_dr_path->hop_count; ind2++) 88219820Sjeff if (p_found_dr_path->path[ind2] != 89219820Sjeff p_dr_path->path[ind2]) 90219820Sjeff found_path = FALSE; 91219820Sjeff 92219820Sjeff /* If found_path is TRUE then there is a full match of the path */ 93219820Sjeff if (found_path == TRUE) { 94219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 95219820Sjeff "Given path is in a fault path\n"); 96219820Sjeff res = TRUE; 97219820Sjeff break; 98219820Sjeff } 99219820Sjeff } 100219820Sjeff 101219820Sjeff OSM_LOG_EXIT(p_log); 102219820Sjeff return res; 103219820Sjeff} 104219820Sjeff 105219820Sjeff/********************************************************************** 106219820Sjeff * For a given dr_path - return TRUE if the path should be dropped, 107219820Sjeff * return FALSE otherwise. 108219820Sjeff * The check uses random criteria in order to determine whether or not 109219820Sjeff * the path should be dropped. 110219820Sjeff * First - if not all paths are initialized, it randomally chooses if 111219820Sjeff * to use this path as a fault path or not. 112219820Sjeff * Second - if the path is in the fault paths (meaning - it is equal 113219820Sjeff * to or includes one of the fault paths) - then it randomally chooses 114219820Sjeff * if to drop it or not. 115219820Sjeff **********************************************************************/ 116219820Sjeffboolean_t 117219820Sjeff__osm_pkt_randomizer_process_path(IN osm_log_t * p_log, 118219820Sjeff IN osm_pkt_randomizer_t * p_pkt_rand, 119219820Sjeff IN osm_dr_path_t * p_dr_path) 120219820Sjeff{ 121219820Sjeff boolean_t res = FALSE; 122219820Sjeff static boolean_t rand_value_init = FALSE; 123219820Sjeff static int rand_value; 124219820Sjeff boolean_t in_fault_paths; 125219820Sjeff uint8_t i; 126219820Sjeff char buf[BUF_SIZE]; 127219820Sjeff char line[BUF_SIZE]; 128219820Sjeff 129219820Sjeff OSM_LOG_ENTER(p_log); 130219820Sjeff 131219820Sjeff if (rand_value_init == FALSE) { 132219820Sjeff int seed; 133219820Sjeff#ifdef WIN32 134219820Sjeff SYSTEMTIME st; 135219820Sjeff#else 136219820Sjeff struct timeval tv; 137219820Sjeff struct timezone tz; 138219820Sjeff#endif /* WIN32 */ 139219820Sjeff 140219820Sjeff /* initiate the rand_value according to timeofday */ 141219820Sjeff rand_value_init = TRUE; 142219820Sjeff 143219820Sjeff#ifdef WIN32 144219820Sjeff GetLocalTime(&st); 145219820Sjeff seed = st.wMilliseconds; 146219820Sjeff#else 147219820Sjeff gettimeofday(&tv, &tz); 148219820Sjeff seed = tv.tv_usec; 149219820Sjeff#endif /* WIN32 */ 150219820Sjeff 151219820Sjeff srand(seed); 152219820Sjeff } 153219820Sjeff 154219820Sjeff /* If the hop_count is 1 - then this is a mad down to our local port - don't drop it */ 155219820Sjeff if (p_dr_path->hop_count <= 1) 156219820Sjeff goto Exit; 157219820Sjeff 158219820Sjeff rand_value = rand(); 159219820Sjeff 160219820Sjeff sprintf(buf, "Path: "); 161219820Sjeff /* update the dr_path into the buf */ 162219820Sjeff for (i = 0; i <= p_dr_path->hop_count; i++) { 163219820Sjeff sprintf(line, "[%X]", p_dr_path->path[i]); 164219820Sjeff strcat(buf, line); 165219820Sjeff } 166219820Sjeff 167219820Sjeff /* Check if the path given is in one of the fault paths */ 168219820Sjeff in_fault_paths = 169219820Sjeff __osm_pkt_randomizer_is_path_in_fault_paths(p_log, p_dr_path, 170219820Sjeff p_pkt_rand); 171219820Sjeff 172219820Sjeff /* Check if all paths are initialized */ 173219820Sjeff if (p_pkt_rand->num_paths_initialized < 174219820Sjeff p_pkt_rand->osm_pkt_num_unstable_links) { 175219820Sjeff /* Not all packets are initialized. */ 176219820Sjeff if (in_fault_paths == FALSE) { 177219820Sjeff /* the path is not in the false paths. Check using the rand value 178219820Sjeff if to update it there or not. */ 179219820Sjeff if (rand_value % 180219820Sjeff (p_pkt_rand->osm_pkt_unstable_link_rate) == 0) { 181219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 182219820Sjeff "%s added to the fault_dr_paths list\n" 183219820Sjeff "\t\t\t rand_value:%u, unstable_link_rate:%u \n", 184219820Sjeff buf, rand_value, 185219820Sjeff p_pkt_rand->osm_pkt_unstable_link_rate); 186219820Sjeff 187219820Sjeff /* update the path in the fault paths */ 188219820Sjeff memcpy(& 189219820Sjeff (p_pkt_rand-> 190219820Sjeff fault_dr_paths[p_pkt_rand-> 191219820Sjeff num_paths_initialized]), 192219820Sjeff p_dr_path, sizeof(osm_dr_path_t)); 193219820Sjeff p_pkt_rand->num_paths_initialized++; 194219820Sjeff in_fault_paths = TRUE; 195219820Sjeff } 196219820Sjeff } 197219820Sjeff } 198219820Sjeff 199219820Sjeff if (in_fault_paths == FALSE) { 200219820Sjeff /* If in_fault_paths is FALSE - just ignore the path */ 201219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, "%s not in fault paths\n", buf); 202219820Sjeff goto Exit; 203219820Sjeff } 204219820Sjeff 205219820Sjeff /* The path is in the fault paths. Need to choose (randomally if to drop it 206219820Sjeff or not. */ 207219820Sjeff rand_value = rand(); 208219820Sjeff 209219820Sjeff if (rand_value % (p_pkt_rand->osm_pkt_drop_rate) == 0) { 210219820Sjeff /* drop the current packet */ 211219820Sjeff res = TRUE; 212219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, "Dropping path:%s\n", buf); 213219820Sjeff } 214219820Sjeff 215219820SjeffExit: 216219820Sjeff OSM_LOG_EXIT(p_log); 217219820Sjeff return res; 218219820Sjeff} 219219820Sjeff 220219820Sjeff/********************************************************************** 221219820Sjeff **********************************************************************/ 222219820Sjeffboolean_t 223219820Sjeffosm_pkt_randomizer_mad_drop(IN osm_log_t * p_log, 224219820Sjeff IN osm_pkt_randomizer_t * p_pkt_randomizer, 225219820Sjeff IN const ib_mad_t * p_mad) 226219820Sjeff{ 227219820Sjeff const ib_smp_t *p_smp; 228219820Sjeff boolean_t res = FALSE; 229219820Sjeff osm_dr_path_t dr_path; 230219820Sjeff 231219820Sjeff OSM_LOG_ENTER(p_log); 232219820Sjeff 233219820Sjeff p_smp = (ib_smp_t *) p_mad; 234219820Sjeff 235219820Sjeff if (p_smp->mgmt_class != IB_MCLASS_SUBN_DIR) 236219820Sjeff /* This is a lid route mad. Don't drop it */ 237219820Sjeff goto Exit; 238219820Sjeff 239219820Sjeff osm_dr_path_init(&dr_path, 0, /* The h_bind is not really important for us to save */ 240219820Sjeff p_smp->hop_count, p_smp->initial_path); 241219820Sjeff 242219820Sjeff if (__osm_pkt_randomizer_process_path 243219820Sjeff (p_log, p_pkt_randomizer, &dr_path)) { 244219820Sjeff /* the mad should be dropped o */ 245219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, 246219820Sjeff "mad TID: 0x%" PRIx64 " is being dropped\n", 247219820Sjeff cl_ntoh64(p_smp->trans_id)); 248219820Sjeff res = TRUE; 249219820Sjeff } 250219820Sjeff 251219820SjeffExit: 252219820Sjeff OSM_LOG_EXIT(p_log); 253219820Sjeff return res; 254219820Sjeff} 255219820Sjeff 256219820Sjeff/********************************************************************** 257219820Sjeff **********************************************************************/ 258219820Sjeffib_api_status_t 259219820Sjeffosm_pkt_randomizer_init(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer, 260219820Sjeff IN osm_log_t * p_log) 261219820Sjeff{ 262219820Sjeff uint8_t tmp; 263219820Sjeff ib_api_status_t res = IB_SUCCESS; 264219820Sjeff 265219820Sjeff OSM_LOG_ENTER(p_log); 266219820Sjeff 267219820Sjeff *pp_pkt_randomizer = malloc(sizeof(osm_pkt_randomizer_t)); 268219820Sjeff if (*pp_pkt_randomizer == NULL) { 269219820Sjeff res = IB_INSUFFICIENT_MEMORY; 270219820Sjeff goto Exit; 271219820Sjeff } 272219820Sjeff memset(*pp_pkt_randomizer, 0, sizeof(osm_pkt_randomizer_t)); 273219820Sjeff (*pp_pkt_randomizer)->num_paths_initialized = 0; 274219820Sjeff 275219820Sjeff tmp = atol(getenv("OSM_PKT_DROP_RATE")); 276219820Sjeff (*pp_pkt_randomizer)->osm_pkt_drop_rate = tmp; 277219820Sjeff 278219820Sjeff if (getenv("OSM_PKT_NUM_UNSTABLE_LINKS") != NULL 279219820Sjeff && (tmp = atol(getenv("OSM_PKT_NUM_UNSTABLE_LINKS"))) > 0) 280219820Sjeff (*pp_pkt_randomizer)->osm_pkt_num_unstable_links = tmp; 281219820Sjeff else 282219820Sjeff (*pp_pkt_randomizer)->osm_pkt_num_unstable_links = 1; 283219820Sjeff 284219820Sjeff if (getenv("OSM_PKT_UNSTABLE_LINK_RATE") != NULL 285219820Sjeff && (tmp = atol(getenv("OSM_PKT_UNSTABLE_LINK_RATE"))) > 0) 286219820Sjeff (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = tmp; 287219820Sjeff else 288219820Sjeff (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = 20; 289219820Sjeff 290219820Sjeff OSM_LOG(p_log, OSM_LOG_VERBOSE, "Using OSM_PKT_DROP_RATE=%u \n" 291219820Sjeff "\t\t\t\t OSM_PKT_NUM_UNSTABLE_LINKS=%u \n" 292219820Sjeff "\t\t\t\t OSM_PKT_UNSTABLE_LINK_RATE=%u \n", 293219820Sjeff (*pp_pkt_randomizer)->osm_pkt_drop_rate, 294219820Sjeff (*pp_pkt_randomizer)->osm_pkt_num_unstable_links, 295219820Sjeff (*pp_pkt_randomizer)->osm_pkt_unstable_link_rate); 296219820Sjeff 297219820Sjeff /* allocate the fault_dr_paths variable */ 298219820Sjeff /* It is the number of the paths that will be saved as fault = osm_pkt_num_unstable_links */ 299219820Sjeff (*pp_pkt_randomizer)->fault_dr_paths = malloc(sizeof(osm_dr_path_t) * 300219820Sjeff (*pp_pkt_randomizer)-> 301219820Sjeff osm_pkt_num_unstable_links); 302219820Sjeff if ((*pp_pkt_randomizer)->fault_dr_paths == NULL) { 303219820Sjeff res = IB_INSUFFICIENT_MEMORY; 304219820Sjeff goto Exit; 305219820Sjeff } 306219820Sjeff 307219820Sjeff memset((*pp_pkt_randomizer)->fault_dr_paths, 0, 308219820Sjeff sizeof(osm_dr_path_t) * 309219820Sjeff (*pp_pkt_randomizer)->osm_pkt_num_unstable_links); 310219820Sjeff 311219820SjeffExit: 312219820Sjeff OSM_LOG_EXIT(p_log); 313219820Sjeff return (res); 314219820Sjeff} 315219820Sjeff 316219820Sjeff/********************************************************************** 317219820Sjeff **********************************************************************/ 318219820Sjeffvoid 319219820Sjeffosm_pkt_randomizer_destroy(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer, 320219820Sjeff IN osm_log_t * p_log) 321219820Sjeff{ 322219820Sjeff OSM_LOG_ENTER(p_log); 323219820Sjeff 324219820Sjeff if (*pp_pkt_randomizer != NULL) { 325219820Sjeff free((*pp_pkt_randomizer)->fault_dr_paths); 326219820Sjeff free(*pp_pkt_randomizer); 327219820Sjeff } 328219820Sjeff OSM_LOG_EXIT(p_log); 329219820Sjeff} 330