1321936Shselasky/*
2321936Shselasky * Copyright (c) 2004-2007 Voltaire Inc.  All rights reserved.
3321936Shselasky * Copyright (c) 2007 Xsigo Systems Inc.  All rights reserved.
4321936Shselasky * Copyright (c) 2008 Lawrence Livermore National Laboratory
5321936Shselasky *
6321936Shselasky * This software is available to you under a choice of one of two
7321936Shselasky * licenses.  You may choose to be licensed under the terms of the GNU
8321936Shselasky * General Public License (GPL) Version 2, available from the file
9321936Shselasky * COPYING in the main directory of this source tree, or the
10321936Shselasky * OpenIB.org BSD license below:
11321936Shselasky *
12321936Shselasky *     Redistribution and use in source and binary forms, with or
13321936Shselasky *     without modification, are permitted provided that the following
14321936Shselasky *     conditions are met:
15321936Shselasky *
16321936Shselasky *      - Redistributions of source code must retain the above
17321936Shselasky *        copyright notice, this list of conditions and the following
18321936Shselasky *        disclaimer.
19321936Shselasky *
20321936Shselasky *      - Redistributions in binary form must reproduce the above
21321936Shselasky *        copyright notice, this list of conditions and the following
22321936Shselasky *        disclaimer in the documentation and/or other materials
23321936Shselasky *        provided with the distribution.
24321936Shselasky *
25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32321936Shselasky * SOFTWARE.
33321936Shselasky *
34321936Shselasky */
35321936Shselasky
36321936Shselasky#if HAVE_CONFIG_H
37321936Shselasky#include <config.h>
38321936Shselasky#endif				/* HAVE_CONFIG_H */
39321936Shselasky
40321936Shselasky#define _GNU_SOURCE
41321936Shselasky#include <stdio.h>
42321936Shselasky#include <stdlib.h>
43321936Shselasky#include <sys/types.h>
44321936Shselasky#include <sys/stat.h>
45321936Shselasky#include <unistd.h>
46321936Shselasky#include <fcntl.h>
47321936Shselasky#include <string.h>
48321936Shselasky#include <errno.h>
49321936Shselasky#include <inttypes.h>
50321936Shselasky
51321936Shselasky#include <infiniband/ibnetdisc.h>
52321936Shselasky
53321936Shselasky#include "internal.h"
54321936Shselasky#include "chassis.h"
55321936Shselasky
56321936Shselasky/* For this caching lib, we always cache little endian */
57321936Shselasky
58321936Shselasky/* Cache format
59321936Shselasky *
60321936Shselasky * Bytes 1-4 - magic number
61321936Shselasky * Bytes 5-8 - version number
62321936Shselasky * Bytes 9-12 - node count
63321936Shselasky * Bytes 13-16 - port count
64321936Shselasky * Bytes 17-24 - "from node" guid
65321936Shselasky * Bytes 25-28 - maxhops discovered
66321936Shselasky * Bytes X-Y - nodes (variable length)
67321936Shselasky * Bytes X-Y - ports (variable length)
68321936Shselasky *
69321936Shselasky * Nodes are cached as
70321936Shselasky *
71321936Shselasky * 2 bytes - smalid
72321936Shselasky * 1 byte - smalmc
73321936Shselasky * 1 byte - smaenhsp0 flag
74321936Shselasky * IB_SMP_DATA_SIZE bytes - switchinfo
75321936Shselasky * 8 bytes - guid
76321936Shselasky * 1 byte - type
77321936Shselasky * 1 byte - numports
78321936Shselasky * IB_SMP_DATA_SIZE bytes - info
79321936Shselasky * IB_SMP_DATA_SIZE bytes - nodedesc
80321936Shselasky * 1 byte - number of ports stored
81321936Shselasky * 8 bytes - portguid A
82321936Shselasky * 1 byte - port num A
83321936Shselasky * 8 bytes - portguid B
84321936Shselasky * 1 byte - port num B
85321936Shselasky * ... etc., depending on number of ports stored
86321936Shselasky *
87321936Shselasky * Ports are cached as
88321936Shselasky *
89321936Shselasky * 8 bytes - guid
90321936Shselasky * 1 byte - portnum
91321936Shselasky * 1 byte - external portnum
92321936Shselasky * 2 bytes - base lid
93321936Shselasky * 1 byte - lmc
94321936Shselasky * IB_SMP_DATA_SIZE bytes - info
95321936Shselasky * 8 bytes - node guid port "owned" by
96321936Shselasky * 1 byte - flag indicating if remote port exists
97321936Shselasky * 8 bytes - port guid remotely connected to
98321936Shselasky * 1 byte - port num remotely connected to
99321936Shselasky */
100321936Shselasky
101321936Shselasky/* Structs that hold cache info temporarily before
102321936Shselasky * the real structs can be reconstructed.
103321936Shselasky */
104321936Shselasky
105321936Shselaskytypedef struct ibnd_port_cache_key {
106321936Shselasky	uint64_t guid;
107321936Shselasky	uint8_t portnum;
108321936Shselasky} ibnd_port_cache_key_t;
109321936Shselasky
110321936Shselaskytypedef struct ibnd_node_cache {
111321936Shselasky	ibnd_node_t *node;
112321936Shselasky	uint8_t ports_stored_count;
113321936Shselasky	ibnd_port_cache_key_t *port_cache_keys;
114321936Shselasky	struct ibnd_node_cache *next;
115321936Shselasky	struct ibnd_node_cache *htnext;
116321936Shselasky	int node_stored_to_fabric;
117321936Shselasky} ibnd_node_cache_t;
118321936Shselasky
119321936Shselaskytypedef struct ibnd_port_cache {
120321936Shselasky	ibnd_port_t *port;
121321936Shselasky	uint64_t node_guid;
122321936Shselasky	uint8_t remoteport_flag;
123321936Shselasky	ibnd_port_cache_key_t remoteport_cache_key;
124321936Shselasky	struct ibnd_port_cache *next;
125321936Shselasky	struct ibnd_port_cache *htnext;
126321936Shselasky	int port_stored_to_fabric;
127321936Shselasky} ibnd_port_cache_t;
128321936Shselasky
129321936Shselaskytypedef struct ibnd_fabric_cache {
130321936Shselasky	f_internal_t *f_int;
131321936Shselasky	uint64_t from_node_guid;
132321936Shselasky	ibnd_node_cache_t *nodes_cache;
133321936Shselasky	ibnd_port_cache_t *ports_cache;
134321936Shselasky	ibnd_node_cache_t *nodescachetbl[HTSZ];
135321936Shselasky	ibnd_port_cache_t *portscachetbl[HTSZ];
136321936Shselasky} ibnd_fabric_cache_t;
137321936Shselasky
138321936Shselasky#define IBND_FABRIC_CACHE_BUFLEN  4096
139321936Shselasky#define IBND_FABRIC_CACHE_MAGIC   0x8FE7832B
140321936Shselasky#define IBND_FABRIC_CACHE_VERSION 0x00000001
141321936Shselasky
142321936Shselasky#define IBND_FABRIC_CACHE_COUNT_OFFSET 8
143321936Shselasky
144321936Shselasky#define IBND_FABRIC_CACHE_HEADER_LEN   (28)
145321936Shselasky#define IBND_NODE_CACHE_HEADER_LEN     (15 + IB_SMP_DATA_SIZE*3)
146321936Shselasky#define IBND_PORT_CACHE_KEY_LEN        (8 + 1)
147321936Shselasky#define IBND_PORT_CACHE_LEN            (31 + IB_SMP_DATA_SIZE)
148321936Shselasky
149321936Shselaskystatic ssize_t ibnd_read(int fd, void *buf, size_t count)
150321936Shselasky{
151321936Shselasky	size_t count_done = 0;
152321936Shselasky	ssize_t ret;
153321936Shselasky
154321936Shselasky	while ((count - count_done) > 0) {
155321936Shselasky		ret = read(fd, ((char *) buf) + count_done, count - count_done);
156321936Shselasky		if (ret < 0) {
157321936Shselasky			if (errno == EINTR)
158321936Shselasky				continue;
159321936Shselasky			else {
160321936Shselasky				IBND_DEBUG("read: %s\n", strerror(errno));
161321936Shselasky				return -1;
162321936Shselasky			}
163321936Shselasky		}
164321936Shselasky		if (!ret)
165321936Shselasky			break;
166321936Shselasky		count_done += ret;
167321936Shselasky	}
168321936Shselasky
169321936Shselasky	if (count_done != count) {
170321936Shselasky		IBND_DEBUG("read: read short\n");
171321936Shselasky		return -1;
172321936Shselasky	}
173321936Shselasky
174321936Shselasky	return count_done;
175321936Shselasky}
176321936Shselasky
177321936Shselaskystatic size_t _unmarshall8(uint8_t * inbuf, uint8_t * num)
178321936Shselasky{
179321936Shselasky	(*num) = inbuf[0];
180321936Shselasky
181321936Shselasky	return (sizeof(*num));
182321936Shselasky}
183321936Shselasky
184321936Shselaskystatic size_t _unmarshall16(uint8_t * inbuf, uint16_t * num)
185321936Shselasky{
186321936Shselasky	(*num) = ((uint16_t) inbuf[1] << 8) | inbuf[0];
187321936Shselasky
188321936Shselasky	return (sizeof(*num));
189321936Shselasky}
190321936Shselasky
191321936Shselaskystatic size_t _unmarshall32(uint8_t * inbuf, uint32_t * num)
192321936Shselasky{
193321936Shselasky	(*num) = (uint32_t) inbuf[0];
194321936Shselasky	(*num) |= ((uint32_t) inbuf[1] << 8);
195321936Shselasky	(*num) |= ((uint32_t) inbuf[2] << 16);
196321936Shselasky	(*num) |= ((uint32_t) inbuf[3] << 24);
197321936Shselasky
198321936Shselasky	return (sizeof(*num));
199321936Shselasky}
200321936Shselasky
201321936Shselaskystatic size_t _unmarshall64(uint8_t * inbuf, uint64_t * num)
202321936Shselasky{
203321936Shselasky	(*num) = (uint64_t) inbuf[0];
204321936Shselasky	(*num) |= ((uint64_t) inbuf[1] << 8);
205321936Shselasky	(*num) |= ((uint64_t) inbuf[2] << 16);
206321936Shselasky	(*num) |= ((uint64_t) inbuf[3] << 24);
207321936Shselasky	(*num) |= ((uint64_t) inbuf[4] << 32);
208321936Shselasky	(*num) |= ((uint64_t) inbuf[5] << 40);
209321936Shselasky	(*num) |= ((uint64_t) inbuf[6] << 48);
210321936Shselasky	(*num) |= ((uint64_t) inbuf[7] << 56);
211321936Shselasky
212321936Shselasky	return (sizeof(*num));
213321936Shselasky}
214321936Shselasky
215321936Shselaskystatic size_t _unmarshall_buf(const void *inbuf, void *outbuf, unsigned int len)
216321936Shselasky{
217321936Shselasky	memcpy(outbuf, inbuf, len);
218321936Shselasky
219321936Shselasky	return len;
220321936Shselasky}
221321936Shselasky
222321936Shselaskystatic int _load_header_info(int fd, ibnd_fabric_cache_t * fabric_cache,
223321936Shselasky			     unsigned int *node_count, unsigned int *port_count)
224321936Shselasky{
225321936Shselasky	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
226321936Shselasky	uint32_t magic = 0;
227321936Shselasky	uint32_t version = 0;
228321936Shselasky	size_t offset = 0;
229321936Shselasky	uint32_t tmp32;
230321936Shselasky
231321936Shselasky	if (ibnd_read(fd, buf, IBND_FABRIC_CACHE_HEADER_LEN) < 0)
232321936Shselasky		return -1;
233321936Shselasky
234321936Shselasky	offset += _unmarshall32(buf + offset, &magic);
235321936Shselasky
236321936Shselasky	if (magic != IBND_FABRIC_CACHE_MAGIC) {
237321936Shselasky		IBND_DEBUG("invalid fabric cache file\n");
238321936Shselasky		return -1;
239321936Shselasky	}
240321936Shselasky
241321936Shselasky	offset += _unmarshall32(buf + offset, &version);
242321936Shselasky
243321936Shselasky	if (version != IBND_FABRIC_CACHE_VERSION) {
244321936Shselasky		IBND_DEBUG("invalid fabric cache version\n");
245321936Shselasky		return -1;
246321936Shselasky	}
247321936Shselasky
248321936Shselasky	offset += _unmarshall32(buf + offset, node_count);
249321936Shselasky	offset += _unmarshall32(buf + offset, port_count);
250321936Shselasky
251321936Shselasky	offset += _unmarshall64(buf + offset, &fabric_cache->from_node_guid);
252321936Shselasky	offset += _unmarshall32(buf + offset, &tmp32);
253321936Shselasky	fabric_cache->f_int->fabric.maxhops_discovered = tmp32;
254321936Shselasky
255321936Shselasky	return 0;
256321936Shselasky}
257321936Shselasky
258321936Shselaskystatic void _destroy_ibnd_node_cache(ibnd_node_cache_t * node_cache)
259321936Shselasky{
260321936Shselasky	free(node_cache->port_cache_keys);
261321936Shselasky	if (!node_cache->node_stored_to_fabric && node_cache->node)
262321936Shselasky		destroy_node(node_cache->node);
263321936Shselasky	free(node_cache);
264321936Shselasky}
265321936Shselasky
266321936Shselaskystatic void _destroy_ibnd_fabric_cache(ibnd_fabric_cache_t * fabric_cache)
267321936Shselasky{
268321936Shselasky	ibnd_node_cache_t *node_cache;
269321936Shselasky	ibnd_node_cache_t *node_cache_next;
270321936Shselasky	ibnd_port_cache_t *port_cache;
271321936Shselasky	ibnd_port_cache_t *port_cache_next;
272321936Shselasky
273321936Shselasky	if (!fabric_cache)
274321936Shselasky		return;
275321936Shselasky
276321936Shselasky	node_cache = fabric_cache->nodes_cache;
277321936Shselasky	while (node_cache) {
278321936Shselasky		node_cache_next = node_cache->next;
279321936Shselasky
280321936Shselasky		_destroy_ibnd_node_cache(node_cache);
281321936Shselasky
282321936Shselasky		node_cache = node_cache_next;
283321936Shselasky	}
284321936Shselasky
285321936Shselasky	port_cache = fabric_cache->ports_cache;
286321936Shselasky	while (port_cache) {
287321936Shselasky		port_cache_next = port_cache->next;
288321936Shselasky
289321936Shselasky		if (!port_cache->port_stored_to_fabric && port_cache->port)
290321936Shselasky			free(port_cache->port);
291321936Shselasky		free(port_cache);
292321936Shselasky
293321936Shselasky		port_cache = port_cache_next;
294321936Shselasky	}
295321936Shselasky
296321936Shselasky	free(fabric_cache);
297321936Shselasky}
298321936Shselasky
299321936Shselaskystatic void store_node_cache(ibnd_node_cache_t * node_cache,
300321936Shselasky			     ibnd_fabric_cache_t * fabric_cache)
301321936Shselasky{
302321936Shselasky	int hash_indx = HASHGUID(node_cache->node->guid) % HTSZ;
303321936Shselasky
304321936Shselasky	node_cache->next = fabric_cache->nodes_cache;
305321936Shselasky	fabric_cache->nodes_cache = node_cache;
306321936Shselasky
307321936Shselasky	node_cache->htnext = fabric_cache->nodescachetbl[hash_indx];
308321936Shselasky	fabric_cache->nodescachetbl[hash_indx] = node_cache;
309321936Shselasky}
310321936Shselasky
311321936Shselaskystatic int _load_node(int fd, ibnd_fabric_cache_t * fabric_cache)
312321936Shselasky{
313321936Shselasky	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
314321936Shselasky	ibnd_node_cache_t *node_cache = NULL;
315321936Shselasky	ibnd_node_t *node = NULL;
316321936Shselasky	size_t offset = 0;
317321936Shselasky	uint8_t tmp8;
318321936Shselasky
319321936Shselasky	node_cache = (ibnd_node_cache_t *) malloc(sizeof(ibnd_node_cache_t));
320321936Shselasky	if (!node_cache) {
321321936Shselasky		IBND_DEBUG("OOM: node_cache\n");
322321936Shselasky		return -1;
323321936Shselasky	}
324321936Shselasky	memset(node_cache, '\0', sizeof(ibnd_node_cache_t));
325321936Shselasky
326321936Shselasky	node = (ibnd_node_t *) malloc(sizeof(ibnd_node_t));
327321936Shselasky	if (!node) {
328321936Shselasky		IBND_DEBUG("OOM: node\n");
329321936Shselasky		free(node_cache);
330321936Shselasky		return -1;
331321936Shselasky	}
332321936Shselasky	memset(node, '\0', sizeof(ibnd_node_t));
333321936Shselasky
334321936Shselasky	node_cache->node = node;
335321936Shselasky
336321936Shselasky	if (ibnd_read(fd, buf, IBND_NODE_CACHE_HEADER_LEN) < 0)
337321936Shselasky		goto cleanup;
338321936Shselasky
339321936Shselasky	offset += _unmarshall16(buf + offset, &node->smalid);
340321936Shselasky	offset += _unmarshall8(buf + offset, &node->smalmc);
341321936Shselasky	offset += _unmarshall8(buf + offset, &tmp8);
342321936Shselasky	node->smaenhsp0 = tmp8;
343321936Shselasky	offset += _unmarshall_buf(buf + offset, node->switchinfo,
344321936Shselasky				  IB_SMP_DATA_SIZE);
345321936Shselasky	offset += _unmarshall64(buf + offset, &node->guid);
346321936Shselasky	offset += _unmarshall8(buf + offset, &tmp8);
347321936Shselasky	node->type = tmp8;
348321936Shselasky	offset += _unmarshall8(buf + offset, &tmp8);
349321936Shselasky	node->numports = tmp8;
350321936Shselasky	offset += _unmarshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
351321936Shselasky	offset += _unmarshall_buf(buf + offset, node->nodedesc,
352321936Shselasky				  IB_SMP_DATA_SIZE);
353321936Shselasky
354321936Shselasky	offset += _unmarshall8(buf + offset, &node_cache->ports_stored_count);
355321936Shselasky
356321936Shselasky	if (node_cache->ports_stored_count) {
357321936Shselasky		unsigned int tomalloc = 0;
358321936Shselasky		unsigned int toread = 0;
359321936Shselasky		unsigned int i;
360321936Shselasky
361321936Shselasky		tomalloc =
362321936Shselasky		    sizeof(ibnd_port_cache_key_t) *
363321936Shselasky		    node_cache->ports_stored_count;
364321936Shselasky
365321936Shselasky		toread =
366321936Shselasky		    IBND_PORT_CACHE_KEY_LEN * node_cache->ports_stored_count;
367321936Shselasky
368321936Shselasky		node_cache->port_cache_keys =
369321936Shselasky		    (ibnd_port_cache_key_t *) malloc(tomalloc);
370321936Shselasky		if (!node_cache->port_cache_keys) {
371321936Shselasky			IBND_DEBUG("OOM: node_cache port_cache_keys\n");
372321936Shselasky			goto cleanup;
373321936Shselasky		}
374321936Shselasky
375321936Shselasky		if (ibnd_read(fd, buf, toread) < 0)
376321936Shselasky			goto cleanup;
377321936Shselasky
378321936Shselasky		offset = 0;
379321936Shselasky
380321936Shselasky		for (i = 0; i < node_cache->ports_stored_count; i++) {
381321936Shselasky			offset +=
382321936Shselasky			    _unmarshall64(buf + offset,
383321936Shselasky					  &node_cache->port_cache_keys[i].guid);
384321936Shselasky			offset +=
385321936Shselasky			    _unmarshall8(buf + offset,
386321936Shselasky					 &node_cache->
387321936Shselasky					 port_cache_keys[i].portnum);
388321936Shselasky		}
389321936Shselasky	}
390321936Shselasky
391321936Shselasky	store_node_cache(node_cache, fabric_cache);
392321936Shselasky
393321936Shselasky	return 0;
394321936Shselasky
395321936Shselaskycleanup:
396321936Shselasky	_destroy_ibnd_node_cache(node_cache);
397321936Shselasky	return -1;
398321936Shselasky}
399321936Shselasky
400321936Shselaskystatic void store_port_cache(ibnd_port_cache_t * port_cache,
401321936Shselasky			     ibnd_fabric_cache_t * fabric_cache)
402321936Shselasky{
403321936Shselasky	int hash_indx = HASHGUID(port_cache->port->guid) % HTSZ;
404321936Shselasky
405321936Shselasky	port_cache->next = fabric_cache->ports_cache;
406321936Shselasky	fabric_cache->ports_cache = port_cache;
407321936Shselasky
408321936Shselasky	port_cache->htnext = fabric_cache->portscachetbl[hash_indx];
409321936Shselasky	fabric_cache->portscachetbl[hash_indx] = port_cache;
410321936Shselasky}
411321936Shselasky
412321936Shselaskystatic int _load_port(int fd, ibnd_fabric_cache_t * fabric_cache)
413321936Shselasky{
414321936Shselasky	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
415321936Shselasky	ibnd_port_cache_t *port_cache = NULL;
416321936Shselasky	ibnd_port_t *port = NULL;
417321936Shselasky	size_t offset = 0;
418321936Shselasky	uint8_t tmp8;
419321936Shselasky
420321936Shselasky	port_cache = (ibnd_port_cache_t *) malloc(sizeof(ibnd_port_cache_t));
421321936Shselasky	if (!port_cache) {
422321936Shselasky		IBND_DEBUG("OOM: port_cache\n");
423321936Shselasky		return -1;
424321936Shselasky	}
425321936Shselasky	memset(port_cache, '\0', sizeof(ibnd_port_cache_t));
426321936Shselasky
427321936Shselasky	port = (ibnd_port_t *) malloc(sizeof(ibnd_port_t));
428321936Shselasky	if (!port) {
429321936Shselasky		IBND_DEBUG("OOM: port\n");
430321936Shselasky		free(port_cache);
431321936Shselasky		return -1;
432321936Shselasky	}
433321936Shselasky	memset(port, '\0', sizeof(ibnd_port_t));
434321936Shselasky
435321936Shselasky	port_cache->port = port;
436321936Shselasky
437321936Shselasky	if (ibnd_read(fd, buf, IBND_PORT_CACHE_LEN) < 0)
438321936Shselasky		goto cleanup;
439321936Shselasky
440321936Shselasky	offset += _unmarshall64(buf + offset, &port->guid);
441321936Shselasky	offset += _unmarshall8(buf + offset, &tmp8);
442321936Shselasky	port->portnum = tmp8;
443321936Shselasky	offset += _unmarshall8(buf + offset, &tmp8);
444321936Shselasky	port->ext_portnum = tmp8;
445321936Shselasky	offset += _unmarshall16(buf + offset, &port->base_lid);
446321936Shselasky	offset += _unmarshall8(buf + offset, &port->lmc);
447321936Shselasky	offset += _unmarshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
448321936Shselasky	offset += _unmarshall64(buf + offset, &port_cache->node_guid);
449321936Shselasky	offset += _unmarshall8(buf + offset, &port_cache->remoteport_flag);
450321936Shselasky	offset +=
451321936Shselasky	    _unmarshall64(buf + offset, &port_cache->remoteport_cache_key.guid);
452321936Shselasky	offset +=
453321936Shselasky	    _unmarshall8(buf + offset,
454321936Shselasky			 &port_cache->remoteport_cache_key.portnum);
455321936Shselasky
456321936Shselasky	store_port_cache(port_cache, fabric_cache);
457321936Shselasky
458321936Shselasky	return 0;
459321936Shselasky
460321936Shselaskycleanup:
461321936Shselasky	free(port);
462321936Shselasky	free(port_cache);
463321936Shselasky	return -1;
464321936Shselasky}
465321936Shselasky
466321936Shselaskystatic ibnd_port_cache_t *_find_port(ibnd_fabric_cache_t * fabric_cache,
467321936Shselasky				     ibnd_port_cache_key_t * port_cache_key)
468321936Shselasky{
469321936Shselasky	int hash_indx = HASHGUID(port_cache_key->guid) % HTSZ;
470321936Shselasky	ibnd_port_cache_t *port_cache;
471321936Shselasky
472321936Shselasky	for (port_cache = fabric_cache->portscachetbl[hash_indx];
473321936Shselasky	     port_cache; port_cache = port_cache->htnext) {
474321936Shselasky		if (port_cache->port->guid == port_cache_key->guid
475321936Shselasky		    && port_cache->port->portnum == port_cache_key->portnum)
476321936Shselasky			return port_cache;
477321936Shselasky	}
478321936Shselasky
479321936Shselasky	return NULL;
480321936Shselasky}
481321936Shselasky
482321936Shselaskystatic ibnd_node_cache_t *_find_node(ibnd_fabric_cache_t * fabric_cache,
483321936Shselasky				     uint64_t guid)
484321936Shselasky{
485321936Shselasky	int hash_indx = HASHGUID(guid) % HTSZ;
486321936Shselasky	ibnd_node_cache_t *node_cache;
487321936Shselasky
488321936Shselasky	for (node_cache = fabric_cache->nodescachetbl[hash_indx];
489321936Shselasky	     node_cache; node_cache = node_cache->htnext) {
490321936Shselasky		if (node_cache->node->guid == guid)
491321936Shselasky			return node_cache;
492321936Shselasky	}
493321936Shselasky
494321936Shselasky	return NULL;
495321936Shselasky}
496321936Shselasky
497321936Shselaskystatic int _fill_port(ibnd_fabric_cache_t * fabric_cache, ibnd_node_t * node,
498321936Shselasky		      ibnd_port_cache_key_t * port_cache_key)
499321936Shselasky{
500321936Shselasky	ibnd_port_cache_t *port_cache;
501321936Shselasky
502321936Shselasky	if (!(port_cache = _find_port(fabric_cache, port_cache_key))) {
503321936Shselasky		IBND_DEBUG("Cache invalid: cannot find port\n");
504321936Shselasky		return -1;
505321936Shselasky	}
506321936Shselasky
507321936Shselasky	if (port_cache->port_stored_to_fabric) {
508321936Shselasky		IBND_DEBUG("Cache invalid: duplicate port discovered\n");
509321936Shselasky		return -1;
510321936Shselasky	}
511321936Shselasky
512321936Shselasky	node->ports[port_cache->port->portnum] = port_cache->port;
513321936Shselasky	port_cache->port_stored_to_fabric++;
514321936Shselasky
515321936Shselasky	/* achu: needed if user wishes to re-cache a loaded fabric.
516321936Shselasky	 * Otherwise, mostly unnecessary to do this.
517321936Shselasky	 */
518321936Shselasky	int rc = add_to_portguid_hash(port_cache->port,
519321936Shselasky				      fabric_cache->f_int->fabric.portstbl);
520321936Shselasky	if (rc) {
521321936Shselasky		IBND_DEBUG("Error Occurred when trying"
522321936Shselasky			   " to insert new port guid 0x%016" PRIx64 " to DB\n",
523321936Shselasky			   port_cache->port->guid);
524321936Shselasky	}
525321936Shselasky	return 0;
526321936Shselasky}
527321936Shselasky
528321936Shselaskystatic int _rebuild_nodes(ibnd_fabric_cache_t * fabric_cache)
529321936Shselasky{
530321936Shselasky	ibnd_node_cache_t *node_cache;
531321936Shselasky	ibnd_node_cache_t *node_cache_next;
532321936Shselasky
533321936Shselasky	node_cache = fabric_cache->nodes_cache;
534321936Shselasky	while (node_cache) {
535321936Shselasky		ibnd_node_t *node;
536321936Shselasky		int i;
537321936Shselasky
538321936Shselasky		node_cache_next = node_cache->next;
539321936Shselasky
540321936Shselasky		node = node_cache->node;
541321936Shselasky
542321936Shselasky		/* Insert node into appropriate data structures */
543321936Shselasky
544321936Shselasky		node->next = fabric_cache->f_int->fabric.nodes;
545321936Shselasky		fabric_cache->f_int->fabric.nodes = node;
546321936Shselasky
547321936Shselasky		int rc = add_to_nodeguid_hash(node_cache->node,
548321936Shselasky					      fabric_cache->
549321936Shselasky					      f_int->
550321936Shselasky					      fabric.nodestbl);
551321936Shselasky		if (rc) {
552321936Shselasky			IBND_DEBUG("Error Occurred when trying"
553321936Shselasky				   " to insert new node guid 0x%016" PRIx64 " to DB\n",
554321936Shselasky				   node_cache->node->guid);
555321936Shselasky		}
556321936Shselasky
557321936Shselasky		add_to_type_list(node_cache->node, fabric_cache->f_int);
558321936Shselasky
559321936Shselasky		node_cache->node_stored_to_fabric++;
560321936Shselasky
561321936Shselasky		/* Rebuild node ports array */
562321936Shselasky
563321936Shselasky		if (!(node->ports =
564321936Shselasky		      calloc(sizeof(*node->ports), node->numports + 1))) {
565321936Shselasky			IBND_DEBUG("OOM: node->ports\n");
566321936Shselasky			return -1;
567321936Shselasky		}
568321936Shselasky
569321936Shselasky		for (i = 0; i < node_cache->ports_stored_count; i++) {
570321936Shselasky			if (_fill_port(fabric_cache, node,
571321936Shselasky				       &node_cache->port_cache_keys[i]) < 0)
572321936Shselasky				return -1;
573321936Shselasky		}
574321936Shselasky
575321936Shselasky		node_cache = node_cache_next;
576321936Shselasky	}
577321936Shselasky
578321936Shselasky	return 0;
579321936Shselasky}
580321936Shselasky
581321936Shselaskystatic int _rebuild_ports(ibnd_fabric_cache_t * fabric_cache)
582321936Shselasky{
583321936Shselasky	ibnd_port_cache_t *port_cache;
584321936Shselasky	ibnd_port_cache_t *port_cache_next;
585321936Shselasky
586321936Shselasky	port_cache = fabric_cache->ports_cache;
587321936Shselasky	while (port_cache) {
588321936Shselasky		ibnd_node_cache_t *node_cache;
589321936Shselasky		ibnd_port_cache_t *remoteport_cache;
590321936Shselasky		ibnd_port_t *port;
591321936Shselasky
592321936Shselasky		port_cache_next = port_cache->next;
593321936Shselasky
594321936Shselasky		port = port_cache->port;
595321936Shselasky
596321936Shselasky		if (!(node_cache =
597321936Shselasky		      _find_node(fabric_cache, port_cache->node_guid))) {
598321936Shselasky			IBND_DEBUG("Cache invalid: cannot find node\n");
599321936Shselasky			return -1;
600321936Shselasky		}
601321936Shselasky
602321936Shselasky		port->node = node_cache->node;
603321936Shselasky
604321936Shselasky		if (port_cache->remoteport_flag) {
605321936Shselasky			if (!(remoteport_cache = _find_port(fabric_cache,
606321936Shselasky							    &port_cache->remoteport_cache_key)))
607321936Shselasky			{
608321936Shselasky				IBND_DEBUG
609321936Shselasky				    ("Cache invalid: cannot find remote port\n");
610321936Shselasky				return -1;
611321936Shselasky			}
612321936Shselasky
613321936Shselasky			port->remoteport = remoteport_cache->port;
614321936Shselasky		} else
615321936Shselasky			port->remoteport = NULL;
616321936Shselasky
617321936Shselasky		add_to_portlid_hash(port, fabric_cache->f_int->lid2guid);
618321936Shselasky		port_cache = port_cache_next;
619321936Shselasky	}
620321936Shselasky
621321936Shselasky	return 0;
622321936Shselasky}
623321936Shselasky
624321936Shselaskyibnd_fabric_t *ibnd_load_fabric(const char *file, unsigned int flags)
625321936Shselasky{
626321936Shselasky	unsigned int node_count = 0;
627321936Shselasky	unsigned int port_count = 0;
628321936Shselasky	ibnd_fabric_cache_t *fabric_cache = NULL;
629321936Shselasky	f_internal_t *f_int = NULL;
630321936Shselasky	ibnd_node_cache_t *node_cache = NULL;
631321936Shselasky	int fd = -1;
632321936Shselasky	unsigned int i;
633321936Shselasky
634321936Shselasky	if (!file) {
635321936Shselasky		IBND_DEBUG("file parameter NULL\n");
636321936Shselasky		return NULL;
637321936Shselasky	}
638321936Shselasky
639321936Shselasky	if ((fd = open(file, O_RDONLY)) < 0) {
640321936Shselasky		IBND_DEBUG("open: %s\n", strerror(errno));
641321936Shselasky		return NULL;
642321936Shselasky	}
643321936Shselasky
644321936Shselasky	fabric_cache =
645321936Shselasky	    (ibnd_fabric_cache_t *) malloc(sizeof(ibnd_fabric_cache_t));
646321936Shselasky	if (!fabric_cache) {
647321936Shselasky		IBND_DEBUG("OOM: fabric_cache\n");
648321936Shselasky		goto cleanup;
649321936Shselasky	}
650321936Shselasky	memset(fabric_cache, '\0', sizeof(ibnd_fabric_cache_t));
651321936Shselasky
652321936Shselasky	f_int = allocate_fabric_internal();
653321936Shselasky	if (!f_int) {
654321936Shselasky		IBND_DEBUG("OOM: fabric\n");
655321936Shselasky		goto cleanup;
656321936Shselasky	}
657321936Shselasky
658321936Shselasky	fabric_cache->f_int = f_int;
659321936Shselasky
660321936Shselasky	if (_load_header_info(fd, fabric_cache, &node_count, &port_count) < 0)
661321936Shselasky		goto cleanup;
662321936Shselasky
663321936Shselasky	for (i = 0; i < node_count; i++) {
664321936Shselasky		if (_load_node(fd, fabric_cache) < 0)
665321936Shselasky			goto cleanup;
666321936Shselasky	}
667321936Shselasky
668321936Shselasky	for (i = 0; i < port_count; i++) {
669321936Shselasky		if (_load_port(fd, fabric_cache) < 0)
670321936Shselasky			goto cleanup;
671321936Shselasky	}
672321936Shselasky
673321936Shselasky	/* Special case - find from node */
674321936Shselasky	if (!(node_cache =
675321936Shselasky	      _find_node(fabric_cache, fabric_cache->from_node_guid))) {
676321936Shselasky		IBND_DEBUG("Cache invalid: cannot find from node\n");
677321936Shselasky		goto cleanup;
678321936Shselasky	}
679321936Shselasky	f_int->fabric.from_node = node_cache->node;
680321936Shselasky
681321936Shselasky	if (_rebuild_nodes(fabric_cache) < 0)
682321936Shselasky		goto cleanup;
683321936Shselasky
684321936Shselasky	if (_rebuild_ports(fabric_cache) < 0)
685321936Shselasky		goto cleanup;
686321936Shselasky
687321936Shselasky	if (group_nodes(&f_int->fabric))
688321936Shselasky		goto cleanup;
689321936Shselasky
690321936Shselasky	_destroy_ibnd_fabric_cache(fabric_cache);
691321936Shselasky	close(fd);
692321936Shselasky	return (ibnd_fabric_t *)&f_int->fabric;
693321936Shselasky
694321936Shselaskycleanup:
695321936Shselasky	ibnd_destroy_fabric((ibnd_fabric_t *)f_int);
696321936Shselasky	_destroy_ibnd_fabric_cache(fabric_cache);
697321936Shselasky	close(fd);
698321936Shselasky	return NULL;
699321936Shselasky}
700321936Shselasky
701321936Shselaskystatic ssize_t ibnd_write(int fd, const void *buf, size_t count)
702321936Shselasky{
703321936Shselasky	size_t count_done = 0;
704321936Shselasky	ssize_t ret;
705321936Shselasky
706321936Shselasky	while ((count - count_done) > 0) {
707321936Shselasky		ret = write(fd, ((char *) buf) + count_done, count - count_done);
708321936Shselasky		if (ret < 0) {
709321936Shselasky			if (errno == EINTR)
710321936Shselasky				continue;
711321936Shselasky			else {
712321936Shselasky				IBND_DEBUG("write: %s\n", strerror(errno));
713321936Shselasky				return -1;
714321936Shselasky			}
715321936Shselasky		}
716321936Shselasky		count_done += ret;
717321936Shselasky	}
718321936Shselasky	return count_done;
719321936Shselasky}
720321936Shselasky
721321936Shselaskystatic size_t _marshall8(uint8_t * outbuf, uint8_t num)
722321936Shselasky{
723321936Shselasky	outbuf[0] = num;
724321936Shselasky
725321936Shselasky	return (sizeof(num));
726321936Shselasky}
727321936Shselasky
728321936Shselaskystatic size_t _marshall16(uint8_t * outbuf, uint16_t num)
729321936Shselasky{
730321936Shselasky	outbuf[0] = num & 0x00FF;
731321936Shselasky	outbuf[1] = (num & 0xFF00) >> 8;
732321936Shselasky
733321936Shselasky	return (sizeof(num));
734321936Shselasky}
735321936Shselasky
736321936Shselaskystatic size_t _marshall32(uint8_t * outbuf, uint32_t num)
737321936Shselasky{
738321936Shselasky	outbuf[0] = num & 0x000000FF;
739321936Shselasky	outbuf[1] = (num & 0x0000FF00) >> 8;
740321936Shselasky	outbuf[2] = (num & 0x00FF0000) >> 16;
741321936Shselasky	outbuf[3] = (num & 0xFF000000) >> 24;
742321936Shselasky
743321936Shselasky	return (sizeof(num));
744321936Shselasky}
745321936Shselasky
746321936Shselaskystatic size_t _marshall64(uint8_t * outbuf, uint64_t num)
747321936Shselasky{
748321936Shselasky	outbuf[0] = (uint8_t) num;
749321936Shselasky	outbuf[1] = (uint8_t) (num >> 8);
750321936Shselasky	outbuf[2] = (uint8_t) (num >> 16);
751321936Shselasky	outbuf[3] = (uint8_t) (num >> 24);
752321936Shselasky	outbuf[4] = (uint8_t) (num >> 32);
753321936Shselasky	outbuf[5] = (uint8_t) (num >> 40);
754321936Shselasky	outbuf[6] = (uint8_t) (num >> 48);
755321936Shselasky	outbuf[7] = (uint8_t) (num >> 56);
756321936Shselasky
757321936Shselasky	return (sizeof(num));
758321936Shselasky}
759321936Shselasky
760321936Shselaskystatic size_t _marshall_buf(void *outbuf, const void *inbuf, unsigned int len)
761321936Shselasky{
762321936Shselasky	memcpy(outbuf, inbuf, len);
763321936Shselasky
764321936Shselasky	return len;
765321936Shselasky}
766321936Shselasky
767321936Shselaskystatic int _cache_header_info(int fd, ibnd_fabric_t * fabric)
768321936Shselasky{
769321936Shselasky	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
770321936Shselasky	size_t offset = 0;
771321936Shselasky
772321936Shselasky	/* Store magic number, version, and other important info */
773321936Shselasky	/* For this caching lib, we always assume cached as little endian */
774321936Shselasky
775321936Shselasky	offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_MAGIC);
776321936Shselasky	offset += _marshall32(buf + offset, IBND_FABRIC_CACHE_VERSION);
777321936Shselasky	/* save space for node count */
778321936Shselasky	offset += _marshall32(buf + offset, 0);
779321936Shselasky	/* save space for port count */
780321936Shselasky	offset += _marshall32(buf + offset, 0);
781321936Shselasky	offset += _marshall64(buf + offset, fabric->from_node->guid);
782321936Shselasky	offset += _marshall32(buf + offset, fabric->maxhops_discovered);
783321936Shselasky
784321936Shselasky	if (ibnd_write(fd, buf, offset) < 0)
785321936Shselasky		return -1;
786321936Shselasky
787321936Shselasky	return 0;
788321936Shselasky}
789321936Shselasky
790321936Shselaskystatic int _cache_header_counts(int fd, unsigned int node_count,
791321936Shselasky				unsigned int port_count)
792321936Shselasky{
793321936Shselasky	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
794321936Shselasky	size_t offset = 0;
795321936Shselasky
796321936Shselasky	offset += _marshall32(buf + offset, node_count);
797321936Shselasky	offset += _marshall32(buf + offset, port_count);
798321936Shselasky
799321936Shselasky	if (lseek(fd, IBND_FABRIC_CACHE_COUNT_OFFSET, SEEK_SET) < 0) {
800321936Shselasky		IBND_DEBUG("lseek: %s\n", strerror(errno));
801321936Shselasky		return -1;
802321936Shselasky	}
803321936Shselasky
804321936Shselasky	if (ibnd_write(fd, buf, offset) < 0)
805321936Shselasky		return -1;
806321936Shselasky
807321936Shselasky	return 0;
808321936Shselasky}
809321936Shselasky
810321936Shselaskystatic int _cache_node(int fd, ibnd_node_t * node)
811321936Shselasky{
812321936Shselasky	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
813321936Shselasky	size_t offset = 0;
814321936Shselasky	size_t ports_stored_offset = 0;
815321936Shselasky	uint8_t ports_stored_count = 0;
816321936Shselasky	int i;
817321936Shselasky
818321936Shselasky	offset += _marshall16(buf + offset, node->smalid);
819321936Shselasky	offset += _marshall8(buf + offset, node->smalmc);
820321936Shselasky	offset += _marshall8(buf + offset, (uint8_t) node->smaenhsp0);
821321936Shselasky	offset += _marshall_buf(buf + offset, node->switchinfo,
822321936Shselasky				IB_SMP_DATA_SIZE);
823321936Shselasky	offset += _marshall64(buf + offset, node->guid);
824321936Shselasky	offset += _marshall8(buf + offset, (uint8_t) node->type);
825321936Shselasky	offset += _marshall8(buf + offset, (uint8_t) node->numports);
826321936Shselasky	offset += _marshall_buf(buf + offset, node->info, IB_SMP_DATA_SIZE);
827321936Shselasky	offset += _marshall_buf(buf + offset, node->nodedesc, IB_SMP_DATA_SIZE);
828321936Shselasky	/* need to come back later and store number of stored ports
829321936Shselasky	 * because port entries can be NULL or (in the case of switches)
830321936Shselasky	 * there is an additional port 0 not accounted for in numports.
831321936Shselasky	 */
832321936Shselasky	ports_stored_offset = offset;
833321936Shselasky	offset += sizeof(uint8_t);
834321936Shselasky
835321936Shselasky	for (i = 0; i <= node->numports; i++) {
836321936Shselasky		if (node->ports[i]) {
837321936Shselasky			offset += _marshall64(buf + offset,
838321936Shselasky					      node->ports[i]->guid);
839321936Shselasky			offset += _marshall8(buf + offset,
840321936Shselasky					     (uint8_t) node->ports[i]->portnum);
841321936Shselasky			ports_stored_count++;
842321936Shselasky		}
843321936Shselasky	}
844321936Shselasky
845321936Shselasky	/* go back and store number of port keys stored */
846321936Shselasky	_marshall8(buf + ports_stored_offset, ports_stored_count);
847321936Shselasky
848321936Shselasky	if (ibnd_write(fd, buf, offset) < 0)
849321936Shselasky		return -1;
850321936Shselasky
851321936Shselasky	return 0;
852321936Shselasky}
853321936Shselasky
854321936Shselaskystatic int _cache_port(int fd, ibnd_port_t * port)
855321936Shselasky{
856321936Shselasky	uint8_t buf[IBND_FABRIC_CACHE_BUFLEN];
857321936Shselasky	size_t offset = 0;
858321936Shselasky
859321936Shselasky	offset += _marshall64(buf + offset, port->guid);
860321936Shselasky	offset += _marshall8(buf + offset, (uint8_t) port->portnum);
861321936Shselasky	offset += _marshall8(buf + offset, (uint8_t) port->ext_portnum);
862321936Shselasky	offset += _marshall16(buf + offset, port->base_lid);
863321936Shselasky	offset += _marshall8(buf + offset, port->lmc);
864321936Shselasky	offset += _marshall_buf(buf + offset, port->info, IB_SMP_DATA_SIZE);
865321936Shselasky	offset += _marshall64(buf + offset, port->node->guid);
866321936Shselasky	if (port->remoteport) {
867321936Shselasky		offset += _marshall8(buf + offset, 1);
868321936Shselasky		offset += _marshall64(buf + offset, port->remoteport->guid);
869321936Shselasky		offset += _marshall8(buf + offset, (uint8_t) port->remoteport->portnum);
870321936Shselasky	} else {
871321936Shselasky		offset += _marshall8(buf + offset, 0);
872321936Shselasky		offset += _marshall64(buf + offset, 0);
873321936Shselasky		offset += _marshall8(buf + offset, 0);
874321936Shselasky	}
875321936Shselasky
876321936Shselasky	if (ibnd_write(fd, buf, offset) < 0)
877321936Shselasky		return -1;
878321936Shselasky
879321936Shselasky	return 0;
880321936Shselasky}
881321936Shselasky
882321936Shselaskyint ibnd_cache_fabric(ibnd_fabric_t * fabric, const char *file,
883321936Shselasky		      unsigned int flags)
884321936Shselasky{
885321936Shselasky	struct stat statbuf;
886321936Shselasky	ibnd_node_t *node = NULL;
887321936Shselasky	ibnd_node_t *node_next = NULL;
888321936Shselasky	unsigned int node_count = 0;
889321936Shselasky	ibnd_port_t *port = NULL;
890321936Shselasky	ibnd_port_t *port_next = NULL;
891321936Shselasky	unsigned int port_count = 0;
892321936Shselasky	int fd;
893321936Shselasky	int i;
894321936Shselasky
895321936Shselasky	if (!fabric) {
896321936Shselasky		IBND_DEBUG("fabric parameter NULL\n");
897321936Shselasky		return -1;
898321936Shselasky	}
899321936Shselasky
900321936Shselasky	if (!file) {
901321936Shselasky		IBND_DEBUG("file parameter NULL\n");
902321936Shselasky		return -1;
903321936Shselasky	}
904321936Shselasky
905321936Shselasky	if (!(flags & IBND_CACHE_FABRIC_FLAG_NO_OVERWRITE)) {
906321936Shselasky		if (!stat(file, &statbuf)) {
907321936Shselasky			if (unlink(file) < 0) {
908321936Shselasky				IBND_DEBUG("error removing '%s': %s\n",
909321936Shselasky					   file, strerror(errno));
910321936Shselasky				return -1;
911321936Shselasky			}
912321936Shselasky		}
913321936Shselasky	}
914321936Shselasky	else {
915321936Shselasky		if (!stat(file, &statbuf)) {
916321936Shselasky			IBND_DEBUG("file '%s' already exists\n", file);
917321936Shselasky			return -1;
918321936Shselasky		}
919321936Shselasky	}
920321936Shselasky
921321936Shselasky	if ((fd = open(file, O_CREAT | O_EXCL | O_WRONLY, 0644)) < 0) {
922321936Shselasky		IBND_DEBUG("open: %s\n", strerror(errno));
923321936Shselasky		return -1;
924321936Shselasky	}
925321936Shselasky
926321936Shselasky	if (_cache_header_info(fd, fabric) < 0)
927321936Shselasky		goto cleanup;
928321936Shselasky
929321936Shselasky	node = fabric->nodes;
930321936Shselasky	while (node) {
931321936Shselasky		node_next = node->next;
932321936Shselasky
933321936Shselasky		if (_cache_node(fd, node) < 0)
934321936Shselasky			goto cleanup;
935321936Shselasky
936321936Shselasky		node_count++;
937321936Shselasky		node = node_next;
938321936Shselasky	}
939321936Shselasky
940321936Shselasky	for (i = 0; i < HTSZ; i++) {
941321936Shselasky		port = fabric->portstbl[i];
942321936Shselasky		while (port) {
943321936Shselasky			port_next = port->htnext;
944321936Shselasky
945321936Shselasky			if (_cache_port(fd, port) < 0)
946321936Shselasky				goto cleanup;
947321936Shselasky
948321936Shselasky			port_count++;
949321936Shselasky			port = port_next;
950321936Shselasky		}
951321936Shselasky	}
952321936Shselasky
953321936Shselasky	if (_cache_header_counts(fd, node_count, port_count) < 0)
954321936Shselasky		goto cleanup;
955321936Shselasky
956321936Shselasky	if (close(fd) < 0) {
957321936Shselasky		IBND_DEBUG("close: %s\n", strerror(errno));
958321936Shselasky		goto cleanup;
959321936Shselasky	}
960321936Shselasky
961321936Shselasky	return 0;
962321936Shselasky
963321936Shselaskycleanup:
964321936Shselasky	unlink(file);
965321936Shselasky	close(fd);
966321936Shselasky	return -1;
967321936Shselasky}
968