Blame libvendor/osm_pkt_randomizer.c

Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
Packit Service 54dbc3
 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * This software is available to you under a choice of one of two
Packit Service 54dbc3
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit Service 54dbc3
 * General Public License (GPL) Version 2, available from the file
Packit Service 54dbc3
 * COPYING in the main directory of this source tree, or the
Packit Service 54dbc3
 * OpenIB.org BSD license below:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *     Redistribution and use in source and binary forms, with or
Packit Service 54dbc3
 *     without modification, are permitted provided that the following
Packit Service 54dbc3
 *     conditions are met:
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions of source code must retain the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 *      - Redistributions in binary form must reproduce the above
Packit Service 54dbc3
 *        copyright notice, this list of conditions and the following
Packit Service 54dbc3
 *        disclaimer in the documentation and/or other materials
Packit Service 54dbc3
 *        provided with the distribution.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service 54dbc3
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service 54dbc3
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service 54dbc3
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service 54dbc3
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service 54dbc3
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service 54dbc3
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service 54dbc3
 * SOFTWARE.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
/*
Packit Service 54dbc3
 * Abstract:
Packit Service 54dbc3
 *    Implementation of osm_pkt_randomizer_t.
Packit Service 54dbc3
 *
Packit Service 54dbc3
 */
Packit Service 54dbc3
Packit Service 54dbc3
#if HAVE_CONFIG_H
Packit Service 54dbc3
#  include <config.h>
Packit Service 54dbc3
#endif				/* HAVE_CONFIG_H */
Packit Service 54dbc3
Packit Service 54dbc3
#include <vendor/osm_pkt_randomizer.h>
Packit Service 54dbc3
#include <stdlib.h>
Packit Service 54dbc3
#include <string.h>
Packit Service 54dbc3
Packit Service 54dbc3
#ifndef __WIN__
Packit Service 54dbc3
#include <sys/time.h>
Packit Service 54dbc3
#include <unistd.h>
Packit Service 54dbc3
#endif
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 * Return TRUE if the path is in a fault path, and FALSE otherwise.
Packit Service 54dbc3
 * By in a fault path the meaning is that there is a path in the fault
Packit Service 54dbc3
 * paths that the given path includes it.
Packit Service 54dbc3
 * E.g: if there is a fault path: 0,1,4
Packit Service 54dbc3
 * For the given path: 0,1,4,7 the return value will be TRUE, also for
Packit Service 54dbc3
 * the given path: 0,1,4 the return value will be TRUE, but for
Packit Service 54dbc3
 * the given paths: 0,1 or 0,3,1,4 - the return value will be FALSE.
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
boolean_t
Packit Service 54dbc3
__osm_pkt_randomizer_is_path_in_fault_paths(IN osm_log_t * p_log,
Packit Service 54dbc3
					    IN osm_dr_path_t * p_dr_path,
Packit Service 54dbc3
					    IN osm_pkt_randomizer_t *
Packit Service 54dbc3
					    p_pkt_rand)
Packit Service 54dbc3
{
Packit Service 54dbc3
	boolean_t res = FALSE, found_path;
Packit Service 54dbc3
	osm_dr_path_t *p_found_dr_path;
Packit Service 54dbc3
	uint8_t ind1, ind2;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	for (ind1 = 0; ind1 < p_pkt_rand->num_paths_initialized; ind1++) {
Packit Service 54dbc3
		found_path = TRUE;
Packit Service 54dbc3
		p_found_dr_path = &(p_pkt_rand->fault_dr_paths[ind1]);
Packit Service 54dbc3
		/* if the hop count of the found path is greater than the
Packit Service 54dbc3
		   hop count of the input path - then it is not part of it.
Packit Service 54dbc3
		   Check the next path. */
Packit Service 54dbc3
		if (p_found_dr_path->hop_count > p_dr_path->hop_count)
Packit Service 54dbc3
			continue;
Packit Service 54dbc3
Packit Service 54dbc3
		/* go over all the ports in the found path and see if they match
Packit Service 54dbc3
		   the ports in the input path */
Packit Service 54dbc3
		for (ind2 = 0; ind2 <= p_found_dr_path->hop_count; ind2++)
Packit Service 54dbc3
			if (p_found_dr_path->path[ind2] !=
Packit Service 54dbc3
			    p_dr_path->path[ind2])
Packit Service 54dbc3
				found_path = FALSE;
Packit Service 54dbc3
Packit Service 54dbc3
		/* If found_path is TRUE  then there is a full match of the path */
Packit Service 54dbc3
		if (found_path == TRUE) {
Packit Service 54dbc3
			OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
				"Given path is in a fault path\n");
Packit Service 54dbc3
			res = TRUE;
Packit Service 54dbc3
			break;
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_EXIT(p_log);
Packit Service 54dbc3
	return res;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
/**********************************************************************
Packit Service 54dbc3
 * For a given dr_path - return TRUE if the path should be dropped,
Packit Service 54dbc3
 * return FALSE otherwise.
Packit Service 54dbc3
 * The check uses random criteria in order to determine whether or not
Packit Service 54dbc3
 * the path should be dropped.
Packit Service 54dbc3
 * First - if not all paths are initialized, it randomally chooses if
Packit Service 54dbc3
 * to use this path as a fault path or not.
Packit Service 54dbc3
 * Second - if the path is in the fault paths (meaning - it is equal
Packit Service 54dbc3
 * to or includes one of the fault paths) - then it randomally chooses
Packit Service 54dbc3
 * if to drop it or not.
Packit Service 54dbc3
 **********************************************************************/
Packit Service 54dbc3
boolean_t
Packit Service 54dbc3
__osm_pkt_randomizer_process_path(IN osm_log_t * p_log,
Packit Service 54dbc3
				  IN osm_pkt_randomizer_t * p_pkt_rand,
Packit Service 54dbc3
				  IN osm_dr_path_t * p_dr_path)
Packit Service 54dbc3
{
Packit Service 54dbc3
	boolean_t res = FALSE;
Packit Service 54dbc3
	static boolean_t rand_value_init = FALSE;
Packit Service 54dbc3
	static int rand_value;
Packit Service 54dbc3
	boolean_t in_fault_paths;
Packit Service 54dbc3
	uint8_t i;
Packit Service 54dbc3
	char buf[BUF_SIZE];
Packit Service 54dbc3
	char line[BUF_SIZE];
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	if (rand_value_init == FALSE) {
Packit Service 54dbc3
		int seed;
Packit Service 54dbc3
#ifdef __WIN__
Packit Service 54dbc3
		SYSTEMTIME st;
Packit Service 54dbc3
#else
Packit Service 54dbc3
		struct timeval tv;
Packit Service 54dbc3
		struct timezone tz;
Packit Service 54dbc3
#endif				/*  __WIN__ */
Packit Service 54dbc3
Packit Service 54dbc3
		/* initiate the rand_value according to timeofday */
Packit Service 54dbc3
		rand_value_init = TRUE;
Packit Service 54dbc3
Packit Service 54dbc3
#ifdef __WIN__
Packit Service 54dbc3
		GetLocalTime(&st);
Packit Service 54dbc3
		seed = st.wMilliseconds;
Packit Service 54dbc3
#else
Packit Service 54dbc3
		gettimeofday(&tv, &tz;;
Packit Service 54dbc3
		seed = tv.tv_usec;
Packit Service 54dbc3
#endif				/*  __WIN__ */
Packit Service 54dbc3
Packit Service 54dbc3
		srand(seed);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* If the hop_count is 1 - then this is a mad down to our local port - don't drop it */
Packit Service 54dbc3
	if (p_dr_path->hop_count <= 1)
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
	rand_value = rand();
Packit Service 54dbc3
Packit Service 54dbc3
	sprintf(buf, "Path: ");
Packit Service 54dbc3
	/* update the dr_path into the buf */
Packit Service 54dbc3
	for (i = 0; i <= p_dr_path->hop_count; i++) {
Packit Service 54dbc3
		sprintf(line, "[%X]", p_dr_path->path[i]);
Packit Service 54dbc3
		strcat(buf, line);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* Check if the path given is in one of the fault paths */
Packit Service 54dbc3
	in_fault_paths =
Packit Service 54dbc3
	    __osm_pkt_randomizer_is_path_in_fault_paths(p_log, p_dr_path,
Packit Service 54dbc3
							p_pkt_rand);
Packit Service 54dbc3
Packit Service 54dbc3
	/* Check if all paths are initialized */
Packit Service 54dbc3
	if (p_pkt_rand->num_paths_initialized <
Packit Service 54dbc3
	    p_pkt_rand->osm_pkt_num_unstable_links) {
Packit Service 54dbc3
		/* Not all packets are initialized. */
Packit Service 54dbc3
		if (in_fault_paths == FALSE) {
Packit Service 54dbc3
			/* the path is not in the false paths. Check using the rand value
Packit Service 54dbc3
			   if to update it there or not. */
Packit Service 54dbc3
			if (rand_value %
Packit Service 54dbc3
			    (p_pkt_rand->osm_pkt_unstable_link_rate) == 0) {
Packit Service 54dbc3
				OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
					"%s added to the fault_dr_paths list\n"
Packit Service 54dbc3
					"\t\t\t rand_value:%u, unstable_link_rate:%u \n",
Packit Service 54dbc3
					buf, rand_value,
Packit Service 54dbc3
					p_pkt_rand->osm_pkt_unstable_link_rate);
Packit Service 54dbc3
Packit Service 54dbc3
				/* update the path in the fault paths */
Packit Service 54dbc3
				memcpy(&
Packit Service 54dbc3
				       (p_pkt_rand->
Packit Service 54dbc3
					fault_dr_paths[p_pkt_rand->
Packit Service 54dbc3
						       num_paths_initialized]),
Packit Service 54dbc3
				       p_dr_path, sizeof(osm_dr_path_t));
Packit Service 54dbc3
				p_pkt_rand->num_paths_initialized++;
Packit Service 54dbc3
				in_fault_paths = TRUE;
Packit Service 54dbc3
			}
Packit Service 54dbc3
		}
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	if (in_fault_paths == FALSE) {
Packit Service 54dbc3
		/* If in_fault_paths is FALSE - just ignore the path */
Packit Service 54dbc3
		OSM_LOG(p_log, OSM_LOG_VERBOSE, "%s not in fault paths\n", buf);
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	/* The path is in the fault paths. Need to choose (randomally if to drop it
Packit Service 54dbc3
	   or not. */
Packit Service 54dbc3
	rand_value = rand();
Packit Service 54dbc3
Packit Service 54dbc3
	if (rand_value % (p_pkt_rand->osm_pkt_drop_rate) == 0) {
Packit Service 54dbc3
		/* drop the current packet */
Packit Service 54dbc3
		res = TRUE;
Packit Service 54dbc3
		OSM_LOG(p_log, OSM_LOG_VERBOSE, "Dropping path:%s\n", buf);
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(p_log);
Packit Service 54dbc3
	return res;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
boolean_t
Packit Service 54dbc3
osm_pkt_randomizer_mad_drop(IN osm_log_t * p_log,
Packit Service 54dbc3
			    IN osm_pkt_randomizer_t * p_pkt_randomizer,
Packit Service 54dbc3
			    IN const ib_mad_t * p_mad)
Packit Service 54dbc3
{
Packit Service 54dbc3
	const ib_smp_t *p_smp;
Packit Service 54dbc3
	boolean_t res = FALSE;
Packit Service 54dbc3
	osm_dr_path_t dr_path;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	p_smp = (ib_smp_t *) p_mad;
Packit Service 54dbc3
Packit Service 54dbc3
	if (p_smp->mgmt_class != IB_MCLASS_SUBN_DIR)
Packit Service 54dbc3
		/* This is a lid route mad. Don't drop it */
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
Packit Service 54dbc3
	osm_dr_path_init(&dr_path, p_smp->hop_count, p_smp->initial_path);
Packit Service 54dbc3
Packit Service 54dbc3
	if (__osm_pkt_randomizer_process_path
Packit Service 54dbc3
	    (p_log, p_pkt_randomizer, &dr_path)) {
Packit Service 54dbc3
		/* the mad should be dropped o */
Packit Service 54dbc3
		OSM_LOG(p_log, OSM_LOG_VERBOSE,
Packit Service 54dbc3
			"mad TID: 0x%" PRIx64 " is being dropped\n",
Packit Service 54dbc3
			cl_ntoh64(p_smp->trans_id));
Packit Service 54dbc3
		res = TRUE;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(p_log);
Packit Service 54dbc3
	return res;
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
ib_api_status_t
Packit Service 54dbc3
osm_pkt_randomizer_init(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer,
Packit Service 54dbc3
			IN osm_log_t * p_log)
Packit Service 54dbc3
{
Packit Service 54dbc3
	uint8_t tmp;
Packit Service 54dbc3
	ib_api_status_t res = IB_SUCCESS;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG_ENTER(p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	*pp_pkt_randomizer = malloc(sizeof(osm_pkt_randomizer_t));
Packit Service 54dbc3
	if (*pp_pkt_randomizer == NULL) {
Packit Service 54dbc3
		res = IB_INSUFFICIENT_MEMORY;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
	memset(*pp_pkt_randomizer, 0, sizeof(osm_pkt_randomizer_t));
Packit Service 54dbc3
	(*pp_pkt_randomizer)->num_paths_initialized = 0;
Packit Service 54dbc3
Packit Service 54dbc3
	tmp = atol(getenv("OSM_PKT_DROP_RATE"));
Packit Service 54dbc3
	(*pp_pkt_randomizer)->osm_pkt_drop_rate = tmp;
Packit Service 54dbc3
Packit Service 54dbc3
	if (getenv("OSM_PKT_NUM_UNSTABLE_LINKS") != NULL
Packit Service 54dbc3
	    && (tmp = atol(getenv("OSM_PKT_NUM_UNSTABLE_LINKS"))) > 0)
Packit Service 54dbc3
		(*pp_pkt_randomizer)->osm_pkt_num_unstable_links = tmp;
Packit Service 54dbc3
	else
Packit Service 54dbc3
		(*pp_pkt_randomizer)->osm_pkt_num_unstable_links = 1;
Packit Service 54dbc3
Packit Service 54dbc3
	if (getenv("OSM_PKT_UNSTABLE_LINK_RATE") != NULL
Packit Service 54dbc3
	    && (tmp = atol(getenv("OSM_PKT_UNSTABLE_LINK_RATE"))) > 0)
Packit Service 54dbc3
		(*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = tmp;
Packit Service 54dbc3
	else
Packit Service 54dbc3
		(*pp_pkt_randomizer)->osm_pkt_unstable_link_rate = 20;
Packit Service 54dbc3
Packit Service 54dbc3
	OSM_LOG(p_log, OSM_LOG_VERBOSE, "Using OSM_PKT_DROP_RATE=%u \n"
Packit Service 54dbc3
		"\t\t\t\t OSM_PKT_NUM_UNSTABLE_LINKS=%u \n"
Packit Service 54dbc3
		"\t\t\t\t OSM_PKT_UNSTABLE_LINK_RATE=%u \n",
Packit Service 54dbc3
		(*pp_pkt_randomizer)->osm_pkt_drop_rate,
Packit Service 54dbc3
		(*pp_pkt_randomizer)->osm_pkt_num_unstable_links,
Packit Service 54dbc3
		(*pp_pkt_randomizer)->osm_pkt_unstable_link_rate);
Packit Service 54dbc3
Packit Service 54dbc3
	/* allocate the fault_dr_paths variable */
Packit Service 54dbc3
	/* It is the number of the paths that will be saved as fault = osm_pkt_num_unstable_links */
Packit Service 54dbc3
	(*pp_pkt_randomizer)->fault_dr_paths = malloc(sizeof(osm_dr_path_t) *
Packit Service 54dbc3
						      (*pp_pkt_randomizer)->
Packit Service 54dbc3
						      osm_pkt_num_unstable_links);
Packit Service 54dbc3
	if ((*pp_pkt_randomizer)->fault_dr_paths == NULL) {
Packit Service 54dbc3
		res = IB_INSUFFICIENT_MEMORY;
Packit Service 54dbc3
		goto Exit;
Packit Service 54dbc3
	}
Packit Service 54dbc3
Packit Service 54dbc3
	memset((*pp_pkt_randomizer)->fault_dr_paths, 0,
Packit Service 54dbc3
	       sizeof(osm_dr_path_t) *
Packit Service 54dbc3
	       (*pp_pkt_randomizer)->osm_pkt_num_unstable_links);
Packit Service 54dbc3
Packit Service 54dbc3
Exit:
Packit Service 54dbc3
	OSM_LOG_EXIT(p_log);
Packit Service 54dbc3
	return (res);
Packit Service 54dbc3
}
Packit Service 54dbc3
Packit Service 54dbc3
void
Packit Service 54dbc3
osm_pkt_randomizer_destroy(IN OUT osm_pkt_randomizer_t ** pp_pkt_randomizer,
Packit Service 54dbc3
			   IN osm_log_t * p_log)
Packit Service 54dbc3
{
Packit Service 54dbc3
	OSM_LOG_ENTER(p_log);
Packit Service 54dbc3
Packit Service 54dbc3
	if (*pp_pkt_randomizer != NULL) {
Packit Service 54dbc3
		free((*pp_pkt_randomizer)->fault_dr_paths);
Packit Service 54dbc3
		free(*pp_pkt_randomizer);
Packit Service 54dbc3
	}
Packit Service 54dbc3
	OSM_LOG_EXIT(p_log);
Packit Service 54dbc3
}