Blame libibnetdisc/src/ibnetdisc_cache.c

Packit db064d
/*
Packit db064d
 * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
Packit db064d
 * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
Packit db064d
 * Copyright (c) 2008 Lawrence Livermore National Laboratory
Packit db064d
 *
Packit db064d
 * This software is available to you under a choice of one of two
Packit db064d
 * licenses.  You may choose to be licensed under the terms of the GNU
Packit db064d
 * General Public License (GPL) Version 2, available from the file
Packit db064d
 * COPYING in the main directory of this source tree, or the
Packit db064d
 * OpenIB.org BSD license below:
Packit db064d
 *
Packit db064d
 *     Redistribution and use in source and binary forms, with or
Packit db064d
 *     without modification, are permitted provided that the following
Packit db064d
 *     conditions are met:
Packit db064d
 *
Packit db064d
 *      - Redistributions of source code must retain the above
Packit db064d
 *        copyright notice, this list of conditions and the following
Packit db064d
 *        disclaimer.
Packit db064d
 *
Packit db064d
 *      - Redistributions in binary form must reproduce the above
Packit db064d
 *        copyright notice, this list of conditions and the following
Packit db064d
 *        disclaimer in the documentation and/or other materials
Packit db064d
 *        provided with the distribution.
Packit db064d
 *
Packit db064d
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit db064d
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit db064d
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit db064d
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit db064d
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit db064d
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit db064d
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit db064d
 * SOFTWARE.
Packit db064d
 *
Packit db064d
 */
Packit db064d
Packit db064d
#if HAVE_CONFIG_H
Packit db064d
#include <config.h>
Packit db064d
#endif				/* HAVE_CONFIG_H */
Packit db064d
Packit db064d
#define _GNU_SOURCE
Packit db064d
#include <stdio.h>
Packit db064d
#include <stdlib.h>
Packit db064d
#include <sys/types.h>
Packit db064d
#include <sys/stat.h>
Packit db064d
#include <unistd.h>
Packit db064d
#include <fcntl.h>
Packit db064d
#include <string.h>
Packit db064d
#include <errno.h>
Packit db064d
#include <inttypes.h>
Packit db064d
Packit db064d
#include <infiniband/ibnetdisc.h>
Packit db064d
Packit db064d
#include "internal.h"
Packit db064d
#include "chassis.h"
Packit db064d
Packit db064d
/* For this caching lib, we always cache little endian */
Packit db064d
Packit db064d
/* Cache format
Packit db064d
 *
Packit db064d
 * Bytes 1-4 - magic number
Packit db064d
 * Bytes 5-8 - version number
Packit db064d
 * Bytes 9-12 - node count
Packit db064d
 * Bytes 13-16 - port count
Packit db064d
 * Bytes 17-24 - "from node" guid
Packit db064d
 * Bytes 25-28 - maxhops discovered
Packit db064d
 * Bytes X-Y - nodes (variable length)
Packit db064d
 * Bytes X-Y - ports (variable length)
Packit db064d
 *
Packit db064d
 * Nodes are cached as
Packit db064d
 *
Packit db064d
 * 2 bytes - smalid
Packit db064d
 * 1 byte - smalmc
Packit db064d
 * 1 byte - smaenhsp0 flag
Packit db064d
 * IB_SMP_DATA_SIZE bytes - switchinfo
Packit db064d
 * 8 bytes - guid
Packit db064d
 * 1 byte - type
Packit db064d
 * 1 byte - numports
Packit db064d
 * IB_SMP_DATA_SIZE bytes - info
Packit db064d
 * IB_SMP_DATA_SIZE bytes - nodedesc
Packit db064d
 * 1 byte - number of ports stored
Packit db064d
 * 8 bytes - portguid A
Packit db064d
 * 1 byte - port num A
Packit db064d
 * 8 bytes - portguid B
Packit db064d
 * 1 byte - port num B
Packit db064d
 * ... etc., depending on number of ports stored
Packit db064d
 *
Packit db064d
 * Ports are cached as
Packit db064d
 *
Packit db064d
 * 8 bytes - guid
Packit db064d
 * 1 byte - portnum
Packit db064d
 * 1 byte - external portnum
Packit db064d
 * 2 bytes - base lid
Packit db064d
 * 1 byte - lmc
Packit db064d
 * IB_SMP_DATA_SIZE bytes - info
Packit db064d
 * 8 bytes - node guid port "owned" by
Packit db064d
 * 1 byte - flag indicating if remote port exists
Packit db064d
 * 8 bytes - port guid remotely connected to
Packit db064d
 * 1 byte - port num remotely connected to
Packit db064d
 */
Packit db064d
Packit db064d
/* Structs that hold cache info temporarily before
Packit db064d
 * the real structs can be reconstructed.
Packit db064d
 */
Packit db064d
Packit db064d
typedef struct ibnd_port_cache_key {
Packit db064d
	uint64_t guid;
Packit db064d
	uint8_t portnum;
Packit db064d
} ibnd_port_cache_key_t;
Packit db064d
Packit db064d
typedef struct ibnd_node_cache {
Packit db064d
	ibnd_node_t *node;
Packit db064d
	uint8_t ports_stored_count;
Packit db064d
	ibnd_port_cache_key_t *port_cache_keys;
Packit db064d
	struct ibnd_node_cache *next;
Packit db064d
	struct ibnd_node_cache *htnext;
Packit db064d
	int node_stored_to_fabric;
Packit db064d
} ibnd_node_cache_t;
Packit db064d
Packit db064d
typedef struct ibnd_port_cache {
Packit db064d
	ibnd_port_t *port;
Packit db064d
	uint64_t node_guid;
Packit db064d
	uint8_t remoteport_flag;
Packit db064d
	ibnd_port_cache_key_t remoteport_cache_key;
Packit db064d
	struct ibnd_port_cache *next;
Packit db064d
	struct ibnd_port_cache *htnext;
Packit db064d
	int port_stored_to_fabric;
Packit db064d
} ibnd_port_cache_t;
Packit db064d
Packit db064d
typedef struct ibnd_fabric_cache {
Packit db064d
	f_internal_t *f_int;
Packit db064d
	uint64_t from_node_guid;
Packit db064d
	ibnd_node_cache_t *nodes_cache;
Packit db064d
	ibnd_port_cache_t *ports_cache;
Packit db064d
	ibnd_node_cache_t *nodescachetbl[HTSZ];
Packit db064d
	ibnd_port_cache_t *portscachetbl[HTSZ];
Packit db064d
} ibnd_fabric_cache_t;
Packit db064d
Packit db064d
#define IBND_FABRIC_CACHE_BUFLEN  4096
Packit db064d
#define IBND_FABRIC_CACHE_MAGIC   0x8FE7832B
Packit db064d
#define IBND_FABRIC_CACHE_VERSION 0x00000001
Packit db064d
Packit db064d
#define IBND_FABRIC_CACHE_COUNT_OFFSET 8
Packit db064d
Packit db064d
#define IBND_FABRIC_CACHE_HEADER_LEN   (28)
Packit db064d
#define IBND_NODE_CACHE_HEADER_LEN     (15 + IB_SMP_DATA_SIZE*3)
Packit db064d
#define IBND_PORT_CACHE_KEY_LEN        (8 + 1)
Packit db064d
#define IBND_PORT_CACHE_LEN            (31 + IB_SMP_DATA_SIZE)
Packit db064d
Packit db064d
static ssize_t ibnd_read(int fd, void *buf, size_t count)
Packit db064d
{
Packit db064d
	size_t count_done = 0;
Packit db064d
	ssize_t ret;
Packit db064d
Packit db064d
	while ((count - count_done) > 0) {
Packit db064d
		ret = read(fd, ((char *) buf) + count_done, count - count_done);
Packit db064d
		if (ret < 0) {
Packit db064d
			if (errno == EINTR)
Packit db064d
				continue;
Packit db064d
			else {
Packit db064d
				IBND_DEBUG("read: %s\n", strerror(errno));
Packit db064d
				return -1;
Packit db064d
			}
Packit db064d
		}
Packit db064d
		if (!ret)
Packit db064d
			break;
Packit db064d
		count_done += ret;
Packit db064d
	}
Packit db064d
Packit db064d
	if (count_done != count) {
Packit db064d
		IBND_DEBUG("read: read short\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	return count_done;
Packit db064d
}
Packit db064d
Packit db064d
static size_t _unmarshall8(uint8_t * inbuf, uint8_t * num)
Packit db064d
{
Packit db064d
	(*num) = inbuf[0];
Packit db064d
Packit db064d
	return (sizeof(*num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _unmarshall16(uint8_t * inbuf, uint16_t * num)
Packit db064d
{
Packit db064d
	(*num) = ((uint16_t) inbuf[1] << 8) | inbuf[0];
Packit db064d
Packit db064d
	return (sizeof(*num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _unmarshall32(uint8_t * inbuf, uint32_t * num)
Packit db064d
{
Packit db064d
	(*num) = (uint32_t) inbuf[0];
Packit db064d
	(*num) |= ((uint32_t) inbuf[1] << 8);
Packit db064d
	(*num) |= ((uint32_t) inbuf[2] << 16);
Packit db064d
	(*num) |= ((uint32_t) inbuf[3] << 24);
Packit db064d
Packit db064d
	return (sizeof(*num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _unmarshall64(uint8_t * inbuf, uint64_t * num)
Packit db064d
{
Packit db064d
	(*num) = (uint64_t) inbuf[0];
Packit db064d
	(*num) |= ((uint64_t) inbuf[1] << 8);
Packit db064d
	(*num) |= ((uint64_t) inbuf[2] << 16);
Packit db064d
	(*num) |= ((uint64_t) inbuf[3] << 24);
Packit db064d
	(*num) |= ((uint64_t) inbuf[4] << 32);
Packit db064d
	(*num) |= ((uint64_t) inbuf[5] << 40);
Packit db064d
	(*num) |= ((uint64_t) inbuf[6] << 48);
Packit db064d
	(*num) |= ((uint64_t) inbuf[7] << 56);
Packit db064d
Packit db064d
	return (sizeof(*num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _unmarshall_buf(const void *inbuf, void *outbuf, unsigned int len)
Packit db064d
{
Packit db064d
	memcpy(outbuf, inbuf, len);
Packit db064d
Packit db064d
	return len;
Packit db064d
}
Packit db064d
Packit db064d
static int _load_header_info(int fd, ibnd_fabric_cache_t * fabric_cache,
Packit db064d
			     unsigned int *node_count, unsigned int *port_count)
Packit db064d
{
Packit db064d
	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
Packit db064d
	uint32_t magic = 0;
Packit db064d
	uint32_t version = 0;
Packit db064d
	size_t offset = 0;
Packit db064d
	uint32_t tmp32;
Packit db064d
Packit db064d
	if (ibnd_read(fd, buf, IBND_FABRIC_CACHE_HEADER_LEN) < 0)
Packit db064d
		return -1;
Packit db064d
Packit db064d
	offset += _unmarshall32(buf + offset, &magic);
Packit db064d
Packit db064d
	if (magic != IBND_FABRIC_CACHE_MAGIC) {
Packit db064d
		IBND_DEBUG("invalid fabric cache file\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	offset += _unmarshall32(buf + offset, &version);
Packit db064d
Packit db064d
	if (version != IBND_FABRIC_CACHE_VERSION) {
Packit db064d
		IBND_DEBUG("invalid fabric cache version\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	offset += _unmarshall32(buf + offset, node_count);
Packit db064d
	offset += _unmarshall32(buf + offset, port_count);
Packit db064d
Packit db064d
	offset += _unmarshall64(buf + offset, &fabric_cache->from_node_guid);
Packit db064d
	offset += _unmarshall32(buf + offset, &tmp32);
Packit db064d
	fabric_cache->f_int->fabric.maxhops_discovered = tmp32;
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static void _destroy_ibnd_node_cache(ibnd_node_cache_t * node_cache)
Packit db064d
{
Packit db064d
	free(node_cache->port_cache_keys);
Packit db064d
	if (!node_cache->node_stored_to_fabric && node_cache->node)
Packit db064d
		destroy_node(node_cache->node);
Packit db064d
	free(node_cache);
Packit db064d
}
Packit db064d
Packit db064d
static void _destroy_ibnd_fabric_cache(ibnd_fabric_cache_t * fabric_cache)
Packit db064d
{
Packit db064d
	ibnd_node_cache_t *node_cache;
Packit db064d
	ibnd_node_cache_t *node_cache_next;
Packit db064d
	ibnd_port_cache_t *port_cache;
Packit db064d
	ibnd_port_cache_t *port_cache_next;
Packit db064d
Packit db064d
	if (!fabric_cache)
Packit db064d
		return;
Packit db064d
Packit db064d
	node_cache = fabric_cache->nodes_cache;
Packit db064d
	while (node_cache) {
Packit db064d
		node_cache_next = node_cache->next;
Packit db064d
Packit db064d
		_destroy_ibnd_node_cache(node_cache);
Packit db064d
Packit db064d
		node_cache = node_cache_next;
Packit db064d
	}
Packit db064d
Packit db064d
	port_cache = fabric_cache->ports_cache;
Packit db064d
	while (port_cache) {
Packit db064d
		port_cache_next = port_cache->next;
Packit db064d
Packit db064d
		if (!port_cache->port_stored_to_fabric && port_cache->port)
Packit db064d
			free(port_cache->port);
Packit db064d
		free(port_cache);
Packit db064d
Packit db064d
		port_cache = port_cache_next;
Packit db064d
	}
Packit db064d
Packit db064d
	free(fabric_cache);
Packit db064d
}
Packit db064d
Packit db064d
static void store_node_cache(ibnd_node_cache_t * node_cache,
Packit db064d
			     ibnd_fabric_cache_t * fabric_cache)
Packit db064d
{
Packit db064d
	int hash_indx = HASHGUID(node_cache->node->guid) % HTSZ;
Packit db064d
Packit db064d
	node_cache->next = fabric_cache->nodes_cache;
Packit db064d
	fabric_cache->nodes_cache = node_cache;
Packit db064d
Packit db064d
	node_cache->htnext = fabric_cache->nodescachetbl[hash_indx];
Packit db064d
	fabric_cache->nodescachetbl[hash_indx] = node_cache;
Packit db064d
}
Packit db064d
Packit db064d
static int _load_node(int fd, ibnd_fabric_cache_t * fabric_cache)
Packit db064d
{
Packit db064d
	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
Packit db064d
	ibnd_node_cache_t *node_cache = NULL;
Packit db064d
	ibnd_node_t *node = NULL;
Packit db064d
	size_t offset = 0;
Packit db064d
	uint8_t tmp8;
Packit db064d
Packit db064d
	node_cache = (ibnd_node_cache_t *) malloc(sizeof(ibnd_node_cache_t));
Packit db064d
	if (!node_cache) {
Packit db064d
		IBND_DEBUG("OOM: node_cache\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
	memset(node_cache, '\0', sizeof(ibnd_node_cache_t));
Packit db064d
Packit db064d
	node = (ibnd_node_t *) malloc(sizeof(ibnd_node_t));
Packit db064d
	if (!node) {
Packit db064d
		IBND_DEBUG("OOM: node\n");
Packit db064d
		free(node_cache);
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
	memset(node, '\0', sizeof(ibnd_node_t));
Packit db064d
Packit db064d
	node_cache->node = node;
Packit db064d
Packit db064d
	if (ibnd_read(fd, buf, IBND_NODE_CACHE_HEADER_LEN) < 0)
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	offset += _unmarshall16(buf + offset, &node->smalid);
Packit db064d
	offset += _unmarshall8(buf + offset, &node->smalmc);
Packit db064d
	offset += _unmarshall8(buf + offset, &tmp8);
Packit db064d
	node->smaenhsp0 = tmp8;
Packit db064d
	offset += _unmarshall_buf(buf + offset, node->switchinfo,
Packit db064d
				  IB_SMP_DATA_SIZE);
Packit db064d
	offset += _unmarshall64(buf + offset, &node->guid);
Packit db064d
	offset += _unmarshall8(buf + offset, &tmp8);
Packit db064d
	node->type = tmp8;
Packit db064d
	offset += _unmarshall8(buf + offset, &tmp8);
Packit db064d
	node->numports = tmp8;
Packit db064d
	offset += _unmarshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
Packit db064d
	offset += _unmarshall_buf(buf + offset, node->nodedesc,
Packit db064d
				  IB_SMP_DATA_SIZE);
Packit db064d
Packit db064d
	offset += _unmarshall8(buf + offset, &node_cache->ports_stored_count);
Packit db064d
Packit db064d
	if (node_cache->ports_stored_count) {
Packit db064d
		unsigned int tomalloc = 0;
Packit db064d
		unsigned int toread = 0;
Packit db064d
		unsigned int i;
Packit db064d
Packit db064d
		tomalloc =
Packit db064d
		    sizeof(ibnd_port_cache_key_t) *
Packit db064d
		    node_cache->ports_stored_count;
Packit db064d
Packit db064d
		toread =
Packit db064d
		    IBND_PORT_CACHE_KEY_LEN * node_cache->ports_stored_count;
Packit db064d
Packit db064d
		node_cache->port_cache_keys =
Packit db064d
		    (ibnd_port_cache_key_t *) malloc(tomalloc);
Packit db064d
		if (!node_cache->port_cache_keys) {
Packit db064d
			IBND_DEBUG("OOM: node_cache port_cache_keys\n");
Packit db064d
			goto cleanup;
Packit db064d
		}
Packit db064d
Packit db064d
		if (ibnd_read(fd, buf, toread) < 0)
Packit db064d
			goto cleanup;
Packit db064d
Packit db064d
		offset = 0;
Packit db064d
Packit db064d
		for (i = 0; i < node_cache->ports_stored_count; i++) {
Packit db064d
			offset +=
Packit db064d
			    _unmarshall64(buf + offset,
Packit db064d
					  &node_cache->port_cache_keys[i].guid);
Packit db064d
			offset +=
Packit db064d
			    _unmarshall8(buf + offset,
Packit db064d
					 &node_cache->
Packit db064d
					 port_cache_keys[i].portnum);
Packit db064d
		}
Packit db064d
	}
Packit db064d
Packit db064d
	store_node_cache(node_cache, fabric_cache);
Packit db064d
Packit db064d
	return 0;
Packit db064d
Packit db064d
cleanup:
Packit db064d
	_destroy_ibnd_node_cache(node_cache);
Packit db064d
	return -1;
Packit db064d
}
Packit db064d
Packit db064d
static void store_port_cache(ibnd_port_cache_t * port_cache,
Packit db064d
			     ibnd_fabric_cache_t * fabric_cache)
Packit db064d
{
Packit db064d
	int hash_indx = HASHGUID(port_cache->port->guid) % HTSZ;
Packit db064d
Packit db064d
	port_cache->next = fabric_cache->ports_cache;
Packit db064d
	fabric_cache->ports_cache = port_cache;
Packit db064d
Packit db064d
	port_cache->htnext = fabric_cache->portscachetbl[hash_indx];
Packit db064d
	fabric_cache->portscachetbl[hash_indx] = port_cache;
Packit db064d
}
Packit db064d
Packit db064d
static int _load_port(int fd, ibnd_fabric_cache_t * fabric_cache)
Packit db064d
{
Packit db064d
	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
Packit db064d
	ibnd_port_cache_t *port_cache = NULL;
Packit db064d
	ibnd_port_t *port = NULL;
Packit db064d
	size_t offset = 0;
Packit db064d
	uint8_t tmp8;
Packit db064d
Packit db064d
	port_cache = (ibnd_port_cache_t *) malloc(sizeof(ibnd_port_cache_t));
Packit db064d
	if (!port_cache) {
Packit db064d
		IBND_DEBUG("OOM: port_cache\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
	memset(port_cache, '\0', sizeof(ibnd_port_cache_t));
Packit db064d
Packit db064d
	port = (ibnd_port_t *) malloc(sizeof(ibnd_port_t));
Packit db064d
	if (!port) {
Packit db064d
		IBND_DEBUG("OOM: port\n");
Packit db064d
		free(port_cache);
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
	memset(port, '\0', sizeof(ibnd_port_t));
Packit db064d
Packit db064d
	port_cache->port = port;
Packit db064d
Packit db064d
	if (ibnd_read(fd, buf, IBND_PORT_CACHE_LEN) < 0)
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	offset += _unmarshall64(buf + offset, &port->guid);
Packit db064d
	offset += _unmarshall8(buf + offset, &tmp8);
Packit db064d
	port->portnum = tmp8;
Packit db064d
	offset += _unmarshall8(buf + offset, &tmp8);
Packit db064d
	port->ext_portnum = tmp8;
Packit db064d
	offset += _unmarshall16(buf + offset, &port->base_lid);
Packit db064d
	offset += _unmarshall8(buf + offset, &port->lmc);
Packit db064d
	offset += _unmarshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
Packit db064d
	offset += _unmarshall64(buf + offset, &port_cache->node_guid);
Packit db064d
	offset += _unmarshall8(buf + offset, &port_cache->remoteport_flag);
Packit db064d
	offset +=
Packit db064d
	    _unmarshall64(buf + offset, &port_cache->remoteport_cache_key.guid);
Packit db064d
	offset +=
Packit db064d
	    _unmarshall8(buf + offset,
Packit db064d
			 &port_cache->remoteport_cache_key.portnum);
Packit db064d
Packit db064d
	store_port_cache(port_cache, fabric_cache);
Packit db064d
Packit db064d
	return 0;
Packit db064d
Packit db064d
cleanup:
Packit db064d
	free(port);
Packit db064d
	free(port_cache);
Packit db064d
	return -1;
Packit db064d
}
Packit db064d
Packit db064d
static ibnd_port_cache_t *_find_port(ibnd_fabric_cache_t * fabric_cache,
Packit db064d
				     ibnd_port_cache_key_t * port_cache_key)
Packit db064d
{
Packit db064d
	int hash_indx = HASHGUID(port_cache_key->guid) % HTSZ;
Packit db064d
	ibnd_port_cache_t *port_cache;
Packit db064d
Packit db064d
	for (port_cache = fabric_cache->portscachetbl[hash_indx];
Packit db064d
	     port_cache; port_cache = port_cache->htnext) {
Packit db064d
		if (port_cache->port->guid == port_cache_key->guid
Packit db064d
		    && port_cache->port->portnum == port_cache_key->portnum)
Packit db064d
			return port_cache;
Packit db064d
	}
Packit db064d
Packit db064d
	return NULL;
Packit db064d
}
Packit db064d
Packit db064d
static ibnd_node_cache_t *_find_node(ibnd_fabric_cache_t * fabric_cache,
Packit db064d
				     uint64_t guid)
Packit db064d
{
Packit db064d
	int hash_indx = HASHGUID(guid) % HTSZ;
Packit db064d
	ibnd_node_cache_t *node_cache;
Packit db064d
Packit db064d
	for (node_cache = fabric_cache->nodescachetbl[hash_indx];
Packit db064d
	     node_cache; node_cache = node_cache->htnext) {
Packit db064d
		if (node_cache->node->guid == guid)
Packit db064d
			return node_cache;
Packit db064d
	}
Packit db064d
Packit db064d
	return NULL;
Packit db064d
}
Packit db064d
Packit db064d
static int _fill_port(ibnd_fabric_cache_t * fabric_cache, ibnd_node_t * node,
Packit db064d
		      ibnd_port_cache_key_t * port_cache_key)
Packit db064d
{
Packit db064d
	ibnd_port_cache_t *port_cache;
Packit db064d
Packit db064d
	if (!(port_cache = _find_port(fabric_cache, port_cache_key))) {
Packit db064d
		IBND_DEBUG("Cache invalid: cannot find port\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	if (port_cache->port_stored_to_fabric) {
Packit db064d
		IBND_DEBUG("Cache invalid: duplicate port discovered\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	node->ports[port_cache->port->portnum] = port_cache->port;
Packit db064d
	port_cache->port_stored_to_fabric++;
Packit db064d
Packit db064d
	/* achu: needed if user wishes to re-cache a loaded fabric.
Packit db064d
	 * Otherwise, mostly unnecessary to do this.
Packit db064d
	 */
Packit db064d
	int rc = add_to_portguid_hash(port_cache->port,
Packit db064d
				      fabric_cache->f_int->fabric.portstbl);
Packit db064d
	if (rc) {
Packit db064d
		IBND_DEBUG("Error Occurred when trying"
Packit db064d
			   " to insert new port guid 0x%016" PRIx64 " to DB\n",
Packit db064d
			   port_cache->port->guid);
Packit db064d
	}
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static int _rebuild_nodes(ibnd_fabric_cache_t * fabric_cache)
Packit db064d
{
Packit db064d
	ibnd_node_cache_t *node_cache;
Packit db064d
	ibnd_node_cache_t *node_cache_next;
Packit db064d
Packit db064d
	node_cache = fabric_cache->nodes_cache;
Packit db064d
	while (node_cache) {
Packit db064d
		ibnd_node_t *node;
Packit db064d
		int i;
Packit db064d
Packit db064d
		node_cache_next = node_cache->next;
Packit db064d
Packit db064d
		node = node_cache->node;
Packit db064d
Packit db064d
		/* Insert node into appropriate data structures */
Packit db064d
Packit db064d
		node->next = fabric_cache->f_int->fabric.nodes;
Packit db064d
		fabric_cache->f_int->fabric.nodes = node;
Packit db064d
Packit db064d
		int rc = add_to_nodeguid_hash(node_cache->node,
Packit db064d
					      fabric_cache->
Packit db064d
					      f_int->
Packit db064d
					      fabric.nodestbl);
Packit db064d
		if (rc) {
Packit db064d
			IBND_DEBUG("Error Occurred when trying"
Packit db064d
				   " to insert new node guid 0x%016" PRIx64 " to DB\n",
Packit db064d
				   node_cache->node->guid);
Packit db064d
		}
Packit db064d
Packit db064d
		add_to_type_list(node_cache->node, fabric_cache->f_int);
Packit db064d
Packit db064d
		node_cache->node_stored_to_fabric++;
Packit db064d
Packit db064d
		/* Rebuild node ports array */
Packit db064d
Packit db064d
		if (!(node->ports =
Packit db064d
		      calloc(sizeof(*node->ports), node->numports + 1))) {
Packit db064d
			IBND_DEBUG("OOM: node->ports\n");
Packit db064d
			return -1;
Packit db064d
		}
Packit db064d
Packit db064d
		for (i = 0; i < node_cache->ports_stored_count; i++) {
Packit db064d
			if (_fill_port(fabric_cache, node,
Packit db064d
				       &node_cache->port_cache_keys[i]) < 0)
Packit db064d
				return -1;
Packit db064d
		}
Packit db064d
Packit db064d
		node_cache = node_cache_next;
Packit db064d
	}
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static int _rebuild_ports(ibnd_fabric_cache_t * fabric_cache)
Packit db064d
{
Packit db064d
	ibnd_port_cache_t *port_cache;
Packit db064d
	ibnd_port_cache_t *port_cache_next;
Packit db064d
Packit db064d
	port_cache = fabric_cache->ports_cache;
Packit db064d
	while (port_cache) {
Packit db064d
		ibnd_node_cache_t *node_cache;
Packit db064d
		ibnd_port_cache_t *remoteport_cache;
Packit db064d
		ibnd_port_t *port;
Packit db064d
Packit db064d
		port_cache_next = port_cache->next;
Packit db064d
Packit db064d
		port = port_cache->port;
Packit db064d
Packit db064d
		if (!(node_cache =
Packit db064d
		      _find_node(fabric_cache, port_cache->node_guid))) {
Packit db064d
			IBND_DEBUG("Cache invalid: cannot find node\n");
Packit db064d
			return -1;
Packit db064d
		}
Packit db064d
Packit db064d
		port->node = node_cache->node;
Packit db064d
Packit db064d
		if (port_cache->remoteport_flag) {
Packit db064d
			if (!(remoteport_cache = _find_port(fabric_cache,
Packit db064d
							    &port_cache->remoteport_cache_key)))
Packit db064d
			{
Packit db064d
				IBND_DEBUG
Packit db064d
				    ("Cache invalid: cannot find remote port\n");
Packit db064d
				return -1;
Packit db064d
			}
Packit db064d
Packit db064d
			port->remoteport = remoteport_cache->port;
Packit db064d
		} else
Packit db064d
			port->remoteport = NULL;
Packit db064d
Packit db064d
		add_to_portlid_hash(port, fabric_cache->f_int);
Packit db064d
		port_cache = port_cache_next;
Packit db064d
	}
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
ibnd_fabric_t *ibnd_load_fabric(const char *file, unsigned int flags)
Packit db064d
{
Packit db064d
	unsigned int node_count = 0;
Packit db064d
	unsigned int port_count = 0;
Packit db064d
	ibnd_fabric_cache_t *fabric_cache = NULL;
Packit db064d
	f_internal_t *f_int = NULL;
Packit db064d
	ibnd_node_cache_t *node_cache = NULL;
Packit db064d
	int fd = -1;
Packit db064d
	unsigned int i;
Packit db064d
Packit db064d
	if (!file) {
Packit db064d
		IBND_DEBUG("file parameter NULL\n");
Packit db064d
		return NULL;
Packit db064d
	}
Packit db064d
Packit db064d
	if ((fd = open(file, O_RDONLY)) < 0) {
Packit db064d
		IBND_DEBUG("open: %s\n", strerror(errno));
Packit db064d
		return NULL;
Packit db064d
	}
Packit db064d
Packit db064d
	fabric_cache =
Packit db064d
	    (ibnd_fabric_cache_t *) malloc(sizeof(ibnd_fabric_cache_t));
Packit db064d
	if (!fabric_cache) {
Packit db064d
		IBND_DEBUG("OOM: fabric_cache\n");
Packit db064d
		goto cleanup;
Packit db064d
	}
Packit db064d
	memset(fabric_cache, '\0', sizeof(ibnd_fabric_cache_t));
Packit db064d
Packit db064d
	f_int = allocate_fabric_internal();
Packit db064d
	if (!f_int) {
Packit db064d
		IBND_DEBUG("OOM: fabric\n");
Packit db064d
		goto cleanup;
Packit db064d
	}
Packit db064d
Packit db064d
	fabric_cache->f_int = f_int;
Packit db064d
Packit db064d
	if (_load_header_info(fd, fabric_cache, &node_count, &port_count) < 0)
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	for (i = 0; i < node_count; i++) {
Packit db064d
		if (_load_node(fd, fabric_cache) < 0)
Packit db064d
			goto cleanup;
Packit db064d
	}
Packit db064d
Packit db064d
	for (i = 0; i < port_count; i++) {
Packit db064d
		if (_load_port(fd, fabric_cache) < 0)
Packit db064d
			goto cleanup;
Packit db064d
	}
Packit db064d
Packit db064d
	/* Special case - find from node */
Packit db064d
	if (!(node_cache =
Packit db064d
	      _find_node(fabric_cache, fabric_cache->from_node_guid))) {
Packit db064d
		IBND_DEBUG("Cache invalid: cannot find from node\n");
Packit db064d
		goto cleanup;
Packit db064d
	}
Packit db064d
	f_int->fabric.from_node = node_cache->node;
Packit db064d
Packit db064d
	if (_rebuild_nodes(fabric_cache) < 0)
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	if (_rebuild_ports(fabric_cache) < 0)
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	if (group_nodes(&f_int->fabric))
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	_destroy_ibnd_fabric_cache(fabric_cache);
Packit db064d
	close(fd);
Packit db064d
	return (ibnd_fabric_t *)&f_int->fabric;
Packit db064d
Packit db064d
cleanup:
Packit db064d
	ibnd_destroy_fabric((ibnd_fabric_t *)f_int);
Packit db064d
	_destroy_ibnd_fabric_cache(fabric_cache);
Packit db064d
	close(fd);
Packit db064d
	return NULL;
Packit db064d
}
Packit db064d
Packit db064d
static ssize_t ibnd_write(int fd, const void *buf, size_t count)
Packit db064d
{
Packit db064d
	size_t count_done = 0;
Packit db064d
	ssize_t ret;
Packit db064d
Packit db064d
	while ((count - count_done) > 0) {
Packit db064d
		ret = write(fd, ((char *) buf) + count_done, count - count_done);
Packit db064d
		if (ret < 0) {
Packit db064d
			if (errno == EINTR)
Packit db064d
				continue;
Packit db064d
			else {
Packit db064d
				IBND_DEBUG("write: %s\n", strerror(errno));
Packit db064d
				return -1;
Packit db064d
			}
Packit db064d
		}
Packit db064d
		count_done += ret;
Packit db064d
	}
Packit db064d
	return count_done;
Packit db064d
}
Packit db064d
Packit db064d
static size_t _marshall8(uint8_t * outbuf, uint8_t num)
Packit db064d
{
Packit db064d
	outbuf[0] = num;
Packit db064d
Packit db064d
	return (sizeof(num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _marshall16(uint8_t * outbuf, uint16_t num)
Packit db064d
{
Packit db064d
	outbuf[0] = num & 0x00FF;
Packit db064d
	outbuf[1] = (num & 0xFF00) >> 8;
Packit db064d
Packit db064d
	return (sizeof(num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _marshall32(uint8_t * outbuf, uint32_t num)
Packit db064d
{
Packit db064d
	outbuf[0] = num & 0x000000FF;
Packit db064d
	outbuf[1] = (num & 0x0000FF00) >> 8;
Packit db064d
	outbuf[2] = (num & 0x00FF0000) >> 16;
Packit db064d
	outbuf[3] = (num & 0xFF000000) >> 24;
Packit db064d
Packit db064d
	return (sizeof(num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _marshall64(uint8_t * outbuf, uint64_t num)
Packit db064d
{
Packit db064d
	outbuf[0] = (uint8_t) num;
Packit db064d
	outbuf[1] = (uint8_t) (num >> 8);
Packit db064d
	outbuf[2] = (uint8_t) (num >> 16);
Packit db064d
	outbuf[3] = (uint8_t) (num >> 24);
Packit db064d
	outbuf[4] = (uint8_t) (num >> 32);
Packit db064d
	outbuf[5] = (uint8_t) (num >> 40);
Packit db064d
	outbuf[6] = (uint8_t) (num >> 48);
Packit db064d
	outbuf[7] = (uint8_t) (num >> 56);
Packit db064d
Packit db064d
	return (sizeof(num));
Packit db064d
}
Packit db064d
Packit db064d
static size_t _marshall_buf(void *outbuf, const void *inbuf, unsigned int len)
Packit db064d
{
Packit db064d
	memcpy(outbuf, inbuf, len);
Packit db064d
Packit db064d
	return len;
Packit db064d
}
Packit db064d
Packit db064d
static int _cache_header_info(int fd, ibnd_fabric_t * fabric)
Packit db064d
{
Packit db064d
	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
Packit db064d
	size_t offset = 0;
Packit db064d
Packit db064d
	/* Store magic number, version, and other important info */
Packit db064d
	/* For this caching lib, we always assume cached as little endian */
Packit db064d
Packit db064d
	offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_MAGIC);
Packit db064d
	offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_VERSION);
Packit db064d
	/* save space for node count */
Packit db064d
	offset += _marshall32(buf + offset, 0);
Packit db064d
	/* save space for port count */
Packit db064d
	offset += _marshall32(buf + offset, 0);
Packit db064d
	offset += _marshall64(buf + offset, fabric->from_node->guid);
Packit db064d
	offset += _marshall32(buf + offset, fabric->maxhops_discovered);
Packit db064d
Packit db064d
	if (ibnd_write(fd, buf, offset) < 0)
Packit db064d
		return -1;
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static int _cache_header_counts(int fd, unsigned int node_count,
Packit db064d
				unsigned int port_count)
Packit db064d
{
Packit db064d
	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
Packit db064d
	size_t offset = 0;
Packit db064d
Packit db064d
	offset += _marshall32(buf + offset, node_count);
Packit db064d
	offset += _marshall32(buf + offset, port_count);
Packit db064d
Packit db064d
	if (lseek(fd, IBND_FABRIC_CACHE_COUNT_OFFSET, SEEK_SET) < 0) {
Packit db064d
		IBND_DEBUG("lseek: %s\n", strerror(errno));
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	if (ibnd_write(fd, buf, offset) < 0)
Packit db064d
		return -1;
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static int _cache_node(int fd, ibnd_node_t * node)
Packit db064d
{
Packit db064d
	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
Packit db064d
	size_t offset = 0;
Packit db064d
	size_t ports_stored_offset = 0;
Packit db064d
	uint8_t ports_stored_count = 0;
Packit db064d
	int i;
Packit db064d
Packit db064d
	offset += _marshall16(buf + offset, node->smalid);
Packit db064d
	offset += _marshall8(buf + offset, node->smalmc);
Packit db064d
	offset += _marshall8(buf + offset, (uint8_t) node->smaenhsp0);
Packit db064d
	offset += _marshall_buf(buf + offset, node->switchinfo,
Packit db064d
				IB_SMP_DATA_SIZE);
Packit db064d
	offset += _marshall64(buf + offset, node->guid);
Packit db064d
	offset += _marshall8(buf + offset, (uint8_t) node->type);
Packit db064d
	offset += _marshall8(buf + offset, (uint8_t) node->numports);
Packit db064d
	offset += _marshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
Packit db064d
	offset += _marshall_buf(buf + offset, node->nodedesc, IB_SMP_DATA_SIZE);
Packit db064d
	/* need to come back later and store number of stored ports
Packit db064d
	 * because port entries can be NULL or (in the case of switches)
Packit db064d
	 * there is an additional port 0 not accounted for in numports.
Packit db064d
	 */
Packit db064d
	ports_stored_offset = offset;
Packit db064d
	offset += sizeof(uint8_t);
Packit db064d
Packit db064d
	for (i = 0; i <= node->numports; i++) {
Packit db064d
		if (node->ports[i]) {
Packit db064d
			offset += _marshall64(buf + offset,
Packit db064d
					      node->ports[i]->guid);
Packit db064d
			offset += _marshall8(buf + offset,
Packit db064d
					     (uint8_t) node->ports[i]->portnum);
Packit db064d
			ports_stored_count++;
Packit db064d
		}
Packit db064d
	}
Packit db064d
Packit db064d
	/* go back and store number of port keys stored */
Packit db064d
	_marshall8(buf + ports_stored_offset, ports_stored_count);
Packit db064d
Packit db064d
	if (ibnd_write(fd, buf, offset) < 0)
Packit db064d
		return -1;
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
static int _cache_port(int fd, ibnd_port_t * port)
Packit db064d
{
Packit db064d
	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
Packit db064d
	size_t offset = 0;
Packit db064d
Packit db064d
	offset += _marshall64(buf + offset, port->guid);
Packit db064d
	offset += _marshall8(buf + offset, (uint8_t) port->portnum);
Packit db064d
	offset += _marshall8(buf + offset, (uint8_t) port->ext_portnum);
Packit db064d
	offset += _marshall16(buf + offset, port->base_lid);
Packit db064d
	offset += _marshall8(buf + offset, port->lmc);
Packit db064d
	offset += _marshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
Packit db064d
	offset += _marshall64(buf + offset, port->node->guid);
Packit db064d
	if (port->remoteport) {
Packit db064d
		offset += _marshall8(buf + offset, 1);
Packit db064d
		offset += _marshall64(buf + offset, port->remoteport->guid);
Packit db064d
		offset += _marshall8(buf + offset, (uint8_t) port->remoteport->portnum);
Packit db064d
	} else {
Packit db064d
		offset += _marshall8(buf + offset, 0);
Packit db064d
		offset += _marshall64(buf + offset, 0);
Packit db064d
		offset += _marshall8(buf + offset, 0);
Packit db064d
	}
Packit db064d
Packit db064d
	if (ibnd_write(fd, buf, offset) < 0)
Packit db064d
		return -1;
Packit db064d
Packit db064d
	return 0;
Packit db064d
}
Packit db064d
Packit db064d
int ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file,
Packit db064d
		      unsigned int flags)
Packit db064d
{
Packit db064d
	struct stat statbuf;
Packit db064d
	ibnd_node_t *node = NULL;
Packit db064d
	ibnd_node_t *node_next = NULL;
Packit db064d
	unsigned int node_count = 0;
Packit db064d
	ibnd_port_t *port = NULL;
Packit db064d
	ibnd_port_t *port_next = NULL;
Packit db064d
	unsigned int port_count = 0;
Packit db064d
	int fd;
Packit db064d
	int i;
Packit db064d
Packit db064d
	if (!fabric) {
Packit db064d
		IBND_DEBUG("fabric parameter NULL\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	if (!file) {
Packit db064d
		IBND_DEBUG("file parameter NULL\n");
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	if (!(flags & IBND_CACHE_FABRIC_FLAG_NO_OVERWRITE)) {
Packit db064d
		if (!stat(file, &statbuf)) {
Packit db064d
			if (unlink(file) < 0) {
Packit db064d
				IBND_DEBUG("error removing '%s': %s\n",
Packit db064d
					   file, strerror(errno));
Packit db064d
				return -1;
Packit db064d
			}
Packit db064d
		}
Packit db064d
	}
Packit db064d
	else {
Packit db064d
		if (!stat(file, &statbuf)) {
Packit db064d
			IBND_DEBUG("file '%s' already exists\n", file);
Packit db064d
			return -1;
Packit db064d
		}
Packit db064d
	}
Packit db064d
Packit db064d
	if ((fd = open(file, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
Packit db064d
		IBND_DEBUG("open: %s\n", strerror(errno));
Packit db064d
		return -1;
Packit db064d
	}
Packit db064d
Packit db064d
	if (_cache_header_info(fd, fabric) < 0)
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	node = fabric->nodes;
Packit db064d
	while (node) {
Packit db064d
		node_next = node->next;
Packit db064d
Packit db064d
		if (_cache_node(fd, node) < 0)
Packit db064d
			goto cleanup;
Packit db064d
Packit db064d
		node_count++;
Packit db064d
		node = node_next;
Packit db064d
	}
Packit db064d
Packit db064d
	for (i = 0; i < HTSZ; i++) {
Packit db064d
		port = fabric->portstbl[i];
Packit db064d
		while (port) {
Packit db064d
			port_next = port->htnext;
Packit db064d
Packit db064d
			if (_cache_port(fd, port) < 0)
Packit db064d
				goto cleanup;
Packit db064d
Packit db064d
			port_count++;
Packit db064d
			port = port_next;
Packit db064d
		}
Packit db064d
	}
Packit db064d
Packit db064d
	if (_cache_header_counts(fd, node_count, port_count) < 0)
Packit db064d
		goto cleanup;
Packit db064d
Packit db064d
	if (close(fd) < 0) {
Packit db064d
		IBND_DEBUG("close: %s\n", strerror(errno));
Packit db064d
		goto cleanup;
Packit db064d
	}
Packit db064d
Packit db064d
	return 0;
Packit db064d
Packit db064d
cleanup:
Packit db064d
	unlink(file);
Packit db064d
	close(fd);
Packit db064d
	return -1;
Packit db064d
}