]> git.openfabrics.org - ~shefty/ibacm.git/commitdiff
refresh
authorSean Hefty <sean.hefty@intel.com>
Fri, 28 Jun 2013 01:51:18 +0000 (18:51 -0700)
committerSean Hefty <sean.hefty@intel.com>
Fri, 28 Jun 2013 01:51:18 +0000 (18:51 -0700)
meta
patches/add-the-ability-to-preload-the
patches/refresh-temp [deleted file]

diff --git a/meta b/meta
index dbaf4c73c789ef0ecea5134df7f8f4b559c4b7e2..ed6be44b2c2490ada4ac6d48b0ff8b349dc35d23 100644 (file)
--- a/meta
+++ b/meta
@@ -1,14 +1,13 @@
 Version: 1
-Previous: 37fb96c0a99872cb3a2923b60c992f0b6493b6fd
-Head: f24113f2629419c710b65ea73721746fe64a0fd6
+Previous: 9b1680c8abd9bc0744838a5d6f773291080bb122
+Head: 2dacc13e5681622d4c26a91fb6cbf3a8f0c0f06e
 Applied:
   rmcfg: 84d811fcdc9f212f243f82594d613b68aea367c4
   acm_notes-txt-change-dos-forma: d76f683c246786876219d6db213643600734d894
   senddep: df6ba3b66ba1c626913faa98316ccab8585769b9
   man-change-dos-formatting-to-u: 097fb5eb23317212b7473485f7f27b550656b466
   update-ib_acme-1-and-ibacm-1-m: be918fdeebd9c58457aaa3ac40363b9c0bee33ba
-  add-the-ability-to-preload-the: 350f21cb4e9b27d86c90f9b997c984475087f180
-  refresh-temp: f24113f2629419c710b65ea73721746fe64a0fd6
+  add-the-ability-to-preload-the: 2dacc13e5681622d4c26a91fb6cbf3a8f0c0f06e
 Unapplied:
   add-description-of-preloading-: 34a336c9c22434ddd543c9eba7bf1ad16f8d0f23
   increase-buffer-space-for-inet: a4540bf14a2bd24b5e24bec78ee1a7bbcee957b9
index 8493e44010e9d3f7e463ca38a65d9a5cea30cd5b..aa603309066c0caa0504002f079037213d3362d5 100644 (file)
@@ -1,5 +1,5 @@
 Bottom: a9581cc2dd236a5dc404caa8bfdccfab12140aee
-Top:    a9581cc2dd236a5dc404caa8bfdccfab12140aee
+Top:    569b928b9302aee7ab9770574b17e831ffcfb557
 Author: Hal Rosenstock <hal@mellanox.com>
 Date:   2013-06-27 16:48:24 +0300
 
@@ -22,4 +22,427 @@ Signed-off-by: Sean Hefty <sean.hefty@intel.com>
 
 ---
 
-
+diff --git a/linux/osd.h b/linux/osd.h
+index c8278aa..c98aa8e 100644
+--- a/linux/osd.h
++++ b/linux/osd.h
+@@ -1,8 +1,9 @@
+-/*\r
+- * Copyright (c) 2009 Intel Corporation.  All rights reserved.\r
+- *\r
+- * This software is available to you under the OpenFabrics.org BSD license\r
+- * below:\r
++/*
++ * Copyright (c) 2009 Intel Corporation.  All rights reserved.
++ * Copyright (c) 2013 Mellanox Technologies LTD. All rights reserved.
++ *
++ * This software is available to you under the OpenFabrics.org BSD license
++ * below:
+  *\r
+  *     Redistribution and use in source and binary forms, with or\r
+  *     without modification, are permitted provided that the following\r
+@@ -54,12 +55,13 @@
+ #ifndef RDMADIR\r
+ #define RDMADIR "rdma"\r
+ #endif\r
+-#define ACM_CONF_DIR  SYSCONFDIR "/" RDMADIR\r
+-#define ACM_ADDR_FILE "ibacm_addr.cfg"\r
+-#define ACM_OPTS_FILE "ibacm_opts.cfg"\r
+-\r
+-#define LIB_DESTRUCTOR __attribute__((destructor))\r
+-#define CDECL_FUNC\r
++#define ACM_CONF_DIR  SYSCONFDIR "/" RDMADIR
++#define ACM_ADDR_FILE "ibacm_addr.cfg"
++#define ACM_OPTS_FILE "ibacm_opts.cfg"
++#define ACM_PATH_REC_FILE "ibacm_path_records.dump"
++
++#define LIB_DESTRUCTOR __attribute__((destructor))
++#define CDECL_FUNC
\r
+ #define container_of(ptr, type, field) \\r
+       ((type *) ((void *) ptr - offsetof(type, field)))\r
+diff --git a/man/ibacm.1 b/man/ibacm.1
+index 35b79c6..9df6062 100644
+--- a/man/ibacm.1
++++ b/man/ibacm.1
+@@ -1,4 +1,4 @@
+-.TH "ibacm" 1 "2013-06-15" "ibacm" "ibacm" ibacm
++.TH "ibacm" 1 "2013-06-18" "ibacm" "ibacm" ibacm
+ .SH NAME
+ ibacm \- address and route resolution services for InfiniBand.
+ .SH SYNOPSIS
+@@ -145,5 +145,16 @@ request is received from a different QPN than a cached request.
+ limited to 4.
+ .P
+ - The number of multicast groups that an endpoint can support is limited to 2.
++.P
++The ibacm contains several internal caches.  These include caches for GID
++and LID destination addresses.  These caches can be optionally
++preloaded. ibacm supports the OpenSM dump_pr plugin "full" PathRecord
++format which is used to preload these caches.
++The file format is specified in the ibacm_opts.cfg file via the
++path_rec_fmt parameter which should be set to full_opensm_v1 for this file
++format.  Default is none which does not preload these caches.
++See dump_pr.notes.txt in dump_pr for more information on the
++full_opensm_v1 file format and how to configure OpenSM to
++generate this file.
+ .SH "SEE ALSO"
+ ibacm(7), ib_acme(1), rdma_cm(7)
+diff --git a/src/acm.c b/src/acm.c
+index e956b09..1df3ed5 100644
+--- a/src/acm.c
++++ b/src/acm.c
+@@ -1,5 +1,6 @@
+ /*
+  * Copyright (c) 2009-2012 Intel Corporation. All rights reserved.
++ * Copyright (c) 2013 Mellanox Technologies LTD. All rights reserved.
+  *
+  * This software is available to you under the OpenIB.org BSD license
+  * below:
+@@ -49,6 +50,8 @@
+ #define src_out     data[0]
++#define IB_LID_MCAST_START 0xc000
++
+ #define MAX_EP_ADDR 4
+ #define MAX_EP_MC   2
+@@ -74,6 +77,11 @@ enum acm_loopback_prot {
+       ACM_LOOPBACK_PROT_LOCAL
+ };
++enum acm_path_rec_fmt {
++      ACM_PATH_REV_FMT_NONE,
++      ACM_PATH_REV_FMT_OSM_FULL_V1
++};
++
+ /*
+  * Nested locking order: dest -> ep, dest -> port
+  */
+@@ -210,6 +218,7 @@ static atomic_t counter[ACM_MAX_COUNTER];
+ static char *acme = BINDIR "/ib_acme -A";
+ static char *opts_file = ACM_CONF_DIR "/" ACM_OPTS_FILE;
+ static char *addr_file = ACM_CONF_DIR "/" ACM_ADDR_FILE;
++static char path_rec_file[128] = ACM_CONF_DIR "/" ACM_PATH_REC_FILE;
+ static char log_file[128] = "/var/log/ibacm.log";
+ static int log_level = 0;
+ static char lock_file[128] = "/var/run/ibacm.pid";
+@@ -227,6 +236,7 @@ static int send_depth = 1;
+ static int recv_depth = 1024;
+ static uint8_t min_mtu = IBV_MTU_2048;
+ static uint8_t min_rate = IBV_RATE_10_GBPS;
++static enum acm_path_rec_fmt path_rec_fmt = ACM_PATH_REV_FMT_NONE;
+ #define acm_log(level, format, ...) \
+       acm_write(level, "%s: "format, __func__, ## __VA_ARGS__)
+@@ -2444,6 +2454,15 @@ static enum acm_loopback_prot acm_convert_loopback_prot(char *param)
+       return loopback_prot;
+ }
++static enum acm_path_rec_fmt acm_convert_path_rec_fmt(char *param)
++{
++      if (!stricmp("none", param))
++              return ACM_PATH_REV_FMT_NONE;
++      else if (!stricmp("full_opensm_v1", param))
++              return ACM_PATH_REV_FMT_OSM_FULL_V1;
++      return path_rec_fmt;
++}
++
+ static enum ibv_rate acm_get_rate(uint8_t width, uint8_t speed)
+ {
+       switch (width) {
+@@ -2553,6 +2572,224 @@ static FILE *acm_open_addr_file(void)
+       return fopen(addr_file, "r");
+ }
++static void acm_parse_path_records_pass1(FILE *f, uint64_t *lid2guid)
++{
++      char s[128];
++      char *p, *ptr, *p_guid, *p_lid;
++      uint64_t guid;
++      uint16_t lid;
++
++      /* Pass 1 - LID to GUID table */
++      while (fgets(s, sizeof s, f)) {
++              if (s[0] == '#')
++                      continue;
++              if (!(p = strtok_r(s, " \n", &ptr)))
++                      continue;       /* ignore blank lines */
++
++              if (strncmp(p, "Switch", sizeof("Switch") - 1) &&
++                  strncmp(p, "Channel", sizeof("Channel") - 1) &&
++                  strncmp(p, "Router", sizeof("Router") - 1))
++                      continue;
++
++              if (!strncmp(p, "Channel", sizeof("Channel") - 1)) {
++                      p = strtok_r(NULL, " ", &ptr); /* skip 'Adapter' */
++                      if (!p)
++                              continue;
++              }
++
++              p_guid = strtok_r(NULL, ",", &ptr);
++              if (!p_guid)
++                      continue;
++
++              guid = (uint64_t) strtoull(p_guid, NULL, 16);
++
++              ptr = strstr(ptr, "base LID");
++              if (!ptr)
++                      continue;
++              ptr += sizeof("base LID");
++              p_lid = strtok_r(NULL, ",", &ptr);
++              if (!p_lid)
++                      continue;
++
++              lid = (uint16_t) strtoul(p_lid, NULL, 0);
++              if (lid >= IB_LID_MCAST_START)
++                      continue;
++              if (lid2guid[lid])
++                      acm_log(0, "ERROR - duplicate lid %u\n", lid);
++              else
++                      lid2guid[lid] = htonll(guid);
++      }
++}
++
++static int acm_parse_path_records_pass2(FILE *f, uint64_t *lid2guid,
++                                      struct acm_ep *ep)
++{
++      union ibv_gid sgid, dgid;
++      struct ibv_port_attr attr = { 0 };
++      struct acm_dest *dest;
++      char s[128];
++      char *p, *ptr, *p_guid, *p_lid;
++      uint64_t guid;
++      uint16_t lid, dlid;
++      int sl, mtu, rate;
++      int ret = 1, i;
++      uint8_t addr[ACM_MAX_ADDRESS];
++      uint8_t addr_type;
++
++      ibv_query_gid(ep->port->dev->verbs, ep->port->port_num, 0, &sgid);
++
++      /* Pass 2 - Path records for source to all destinations */
++
++      while (fgets(s, sizeof s, f)) {
++              if (s[0] == '#')
++                      continue;
++              if (!(p = strtok_r(s, " \n", &ptr)))
++                      continue;       /* ignore blank lines */
++
++              if (strncmp(p, "Switch", sizeof("Switch") - 1) &&
++                  strncmp(p, "Channel", sizeof("Channel") - 1) &&
++                  strncmp(p, "Router", sizeof("Router") - 1))
++                      continue;
++
++              if (!strncmp(p, "Channel", sizeof("Channel") - 1)) {
++                      p = strtok_r(NULL, " ", &ptr); /* skip 'Adapter' */
++                      if (!p)
++                              continue;
++              }
++
++              p_guid = strtok_r(NULL, ",", &ptr);
++              if (!p_guid)
++                      continue;
++
++              guid = (uint64_t) strtoull(p_guid, NULL, 16);
++              if (guid != ntohll(sgid.global.interface_id))
++                      continue;
++
++              ptr = strstr(ptr, "base LID");
++              if (!ptr)
++                      continue;
++              ptr += sizeof("base LID");
++              p_lid = strtok_r(NULL, ",", &ptr);
++              if (!p_lid)
++                      continue;
++
++              lid = (uint16_t) strtoul(p_lid, NULL, 0);
++              if (lid != ep->port->lid)
++                      continue;
++              ibv_query_port(ep->port->dev->verbs, ep->port->port_num, &attr);
++              ret = 0;
++              break;
++      }
++
++      while (fgets(s, sizeof s, f)) {
++              if (s[0] == '#')
++                      continue;
++              if (!(p = strtok_r(s, " \n", &ptr)))
++                      continue;       /* ignore blank lines */
++
++              if (!strncmp(p, "Switch", sizeof("Switch") - 1) ||
++                  !strncmp(p, "Channel", sizeof("Channel") - 1) ||
++                  !strncmp(p, "Router", sizeof("Router") - 1))
++                      break;
++
++              dlid = strtoul(p, NULL, 0);
++
++              p = strtok_r(NULL, ":", &ptr);
++              if (!p)
++                      continue;
++              if (strcmp(p, "UNREACHABLE") == 0)
++                      continue;
++              sl = atoi(p);
++
++              p = strtok_r(NULL, ":", &ptr);
++              if (!p)
++                      continue;
++              mtu = atoi(p);
++
++              p = strtok_r(NULL, ":", &ptr);
++              if (!p)
++                      continue;
++              rate = atoi(p);
++
++              if (!lid2guid[dlid]) {
++                      acm_log(0, "ERROR - dlid %u not found in lid2guid table\n", dlid);
++                      continue;
++              }
++
++              dgid.global.subnet_prefix = sgid.global.subnet_prefix;
++              dgid.global.interface_id = lid2guid[dlid];
++
++              for (i = 0; i < 2; i++) {
++                      memset(addr, 0, ACM_MAX_ADDRESS);
++                      if (i == 0) {
++                              addr_type = ACM_ADDRESS_LID;
++                              *((uint16_t *) addr) = htons(dlid);
++                      } else {
++                              addr_type = ACM_ADDRESS_GID;
++                              memcpy(addr, &dgid, sizeof(dgid));
++                      }
++                      dest = acm_acquire_dest(ep, addr_type, addr);
++                      if (!dest) {
++                              acm_log(0, "ERROR - unable to create dest\n");
++                              break;
++                      }
++
++                      dest->path.sgid = sgid;
++                      dest->path.slid = htons(ep->port->lid);
++                      dest->path.dgid = dgid;
++                      dest->path.dlid = htons(dlid);
++                      dest->path.reversible_numpath = IBV_PATH_RECORD_REVERSIBLE;
++                      dest->path.pkey = htons(ep->pkey);
++                      dest->path.mtu = (uint8_t) mtu;
++                      dest->path.rate = (uint8_t) rate;
++                      dest->path.qosclass_sl = htons((uint16_t) sl & 0xF);
++                      if (dlid == ep->port->lid) {
++                              dest->path.packetlifetime = 0;
++                              dest->addr_timeout = (uint64_t)~0ULL;
++                              dest->route_timeout = (uint64_t)~0ULL;
++                      } else {
++                              dest->path.packetlifetime = attr.subnet_timeout;
++                              dest->addr_timeout = time_stamp_min() + (unsigned) addr_timeout;
++                              dest->route_timeout = time_stamp_min() + (unsigned) route_timeout;
++                      }
++                      dest->remote_qpn = 1;
++                      dest->state = ACM_READY;
++                      acm_put_dest(dest);
++                      acm_log(1, "added cached dest %s\n", dest->name);
++              }
++      }
++      return ret;
++}
++
++static int acm_parse_path_records(struct acm_ep *ep)
++{
++      FILE *f;
++      uint64_t *lid2guid;
++      int ret = 1;
++
++      if (!(f = fopen(path_rec_file, "r"))) {
++              acm_log(0, "ERROR - couldn't open %s\n", path_rec_file);
++              return ret;
++      }
++
++      lid2guid = calloc(IB_LID_MCAST_START, sizeof(*lid2guid));
++      if (!lid2guid) {
++              acm_log(0, "ERROR - no memory for path record parsing\n");
++              goto err;
++      }
++
++      if (path_rec_fmt == ACM_PATH_REV_FMT_OSM_FULL_V1) {
++              acm_parse_path_records_pass1(f, lid2guid);
++              rewind(f);
++              ret = acm_parse_path_records_pass2(f, lid2guid, ep);
++      }
++
++      free(lid2guid);
++err:
++      fclose(f);
++      return ret;
++}
++
+ static int acm_assign_ep_names(struct acm_ep *ep)
+ {
+       FILE *faddr;
+@@ -2802,6 +3039,13 @@ static void acm_ep_up(struct acm_port *port, uint16_t pkey_index)
+       lock_acquire(&port->lock);
+       DListInsertHead(&ep->entry, &port->ep_list);
+       lock_release(&port->lock);
++
++      if (path_rec_fmt == ACM_PATH_REV_FMT_OSM_FULL_V1) {
++              ret = acm_parse_path_records(ep);
++              if (ret)
++                      acm_log(1, "unable to find ep in path records\n");
++      }
++
+       return;
+ err2:
+@@ -3114,6 +3358,10 @@ static void acm_set_options(void)
+                       min_mtu = acm_convert_mtu(atoi(value));
+               else if (!stricmp("min_rate", opt))
+                       min_rate = acm_convert_rate(atoi(value));
++              else if (!stricmp("path_rec_fmt", opt))
++                      path_rec_fmt = acm_convert_path_rec_fmt(value);
++              else if (!stricmp("path_rec_file", opt))
++                      strcpy(path_rec_file, value);
+       }
+       fclose(f);
+@@ -3137,6 +3385,8 @@ static void acm_log_options(void)
+       acm_log(0, "receive depth %d\n", recv_depth);
+       acm_log(0, "minimum mtu %d\n", min_mtu);
+       acm_log(0, "minimum rate %d\n", min_rate);
++      acm_log(0, "path record format %d\n", path_rec_fmt);
++      acm_log(0, "path record file %s\n", path_rec_file);
+ }
+ static FILE *acm_open_log(void)
+@@ -3200,9 +3450,9 @@ static void show_usage(char *program)
+       printf("   [-D]             - run as a daemon (default)\n");
+       printf("   [-P]             - run as a standard process\n");
+       printf("   [-A addr_file]   - address configuration file\n");
+-      printf("                      (default %s/%s\n", ACM_CONF_DIR, ACM_ADDR_FILE);
++      printf("                      (default %s/%s)\n", ACM_CONF_DIR, ACM_ADDR_FILE);
+       printf("   [-O option_file] - option configuration file\n");
+-      printf("                      (default %s/%s\n", ACM_CONF_DIR, ACM_OPTS_FILE);
++      printf("                      (default %s/%s)\n", ACM_CONF_DIR, ACM_OPTS_FILE);
+ }
+ int CDECL_FUNC main(int argc, char **argv)
+diff --git a/src/acme.c b/src/acme.c
+index 1abb644..7c87aa1 100644
+--- a/src/acme.c
++++ b/src/acme.c
+@@ -244,6 +244,18 @@ static void gen_opts_temp(FILE *f)
+       fprintf(f, "\n");
+       fprintf(f, "min_rate 10\n");
+       fprintf(f, "\n");
++      fprintf(f, "# path_rec_fmt:\n");
++      fprintf(f, "# Indicates format of optional path records file for preloading ACM cache.\n");
++      fprintf(f, "# Supported formats are:\n");
++      fprintf(f, "# none - No path record file preloading (default)\n");
++      fprintf(f, "# full_opensm_v1 - OpenSM \"full\" path records dump file format (version 1)\n");
++      fprintf(f, "\n");
++      fprintf(f, "path_rec_fmt none\n");
++      fprintf(f, "\n");
++      fprintf(f, "# path_rec_file:\n");
++      fprintf(f, "# If path_rec_fmt is other than \"none\", full pathname of path records file\n");
++      fprintf(f, "# to use for preloading the ACM cache.  Default is ACM_CONF_DIR/ibacm_path_records.dump\n");
++      fprintf(f, "\n");
+ }
+ static int open_dir(void)
diff --git a/patches/refresh-temp b/patches/refresh-temp
deleted file mode 100644 (file)
index b988347..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-Bottom: a9581cc2dd236a5dc404caa8bfdccfab12140aee
-Top:    569b928b9302aee7ab9770574b17e831ffcfb557
-Author: Sean Hefty <sean.hefty@intel.com>
-Date:   2013-06-27 18:51:18 -0700
-
-Refresh of add-the-ability-to-preload-the
-
----
-
-diff --git a/linux/osd.h b/linux/osd.h
-index c8278aa..c98aa8e 100644
---- a/linux/osd.h
-+++ b/linux/osd.h
-@@ -1,8 +1,9 @@
--/*\r
-- * Copyright (c) 2009 Intel Corporation.  All rights reserved.\r
-- *\r
-- * This software is available to you under the OpenFabrics.org BSD license\r
-- * below:\r
-+/*
-+ * Copyright (c) 2009 Intel Corporation.  All rights reserved.
-+ * Copyright (c) 2013 Mellanox Technologies LTD. All rights reserved.
-+ *
-+ * This software is available to you under the OpenFabrics.org BSD license
-+ * below:
-  *\r
-  *     Redistribution and use in source and binary forms, with or\r
-  *     without modification, are permitted provided that the following\r
-@@ -54,12 +55,13 @@
- #ifndef RDMADIR\r
- #define RDMADIR "rdma"\r
- #endif\r
--#define ACM_CONF_DIR  SYSCONFDIR "/" RDMADIR\r
--#define ACM_ADDR_FILE "ibacm_addr.cfg"\r
--#define ACM_OPTS_FILE "ibacm_opts.cfg"\r
--\r
--#define LIB_DESTRUCTOR __attribute__((destructor))\r
--#define CDECL_FUNC\r
-+#define ACM_CONF_DIR  SYSCONFDIR "/" RDMADIR
-+#define ACM_ADDR_FILE "ibacm_addr.cfg"
-+#define ACM_OPTS_FILE "ibacm_opts.cfg"
-+#define ACM_PATH_REC_FILE "ibacm_path_records.dump"
-+
-+#define LIB_DESTRUCTOR __attribute__((destructor))
-+#define CDECL_FUNC
\r
- #define container_of(ptr, type, field) \\r
-       ((type *) ((void *) ptr - offsetof(type, field)))\r
-diff --git a/man/ibacm.1 b/man/ibacm.1
-index 35b79c6..9df6062 100644
---- a/man/ibacm.1
-+++ b/man/ibacm.1
-@@ -1,4 +1,4 @@
--.TH "ibacm" 1 "2013-06-15" "ibacm" "ibacm" ibacm
-+.TH "ibacm" 1 "2013-06-18" "ibacm" "ibacm" ibacm
- .SH NAME
- ibacm \- address and route resolution services for InfiniBand.
- .SH SYNOPSIS
-@@ -145,5 +145,16 @@ request is received from a different QPN than a cached request.
- limited to 4.
- .P
- - The number of multicast groups that an endpoint can support is limited to 2.
-+.P
-+The ibacm contains several internal caches.  These include caches for GID
-+and LID destination addresses.  These caches can be optionally
-+preloaded. ibacm supports the OpenSM dump_pr plugin "full" PathRecord
-+format which is used to preload these caches.
-+The file format is specified in the ibacm_opts.cfg file via the
-+path_rec_fmt parameter which should be set to full_opensm_v1 for this file
-+format.  Default is none which does not preload these caches.
-+See dump_pr.notes.txt in dump_pr for more information on the
-+full_opensm_v1 file format and how to configure OpenSM to
-+generate this file.
- .SH "SEE ALSO"
- ibacm(7), ib_acme(1), rdma_cm(7)
-diff --git a/src/acm.c b/src/acm.c
-index e956b09..1df3ed5 100644
---- a/src/acm.c
-+++ b/src/acm.c
-@@ -1,5 +1,6 @@
- /*
-  * Copyright (c) 2009-2012 Intel Corporation. All rights reserved.
-+ * Copyright (c) 2013 Mellanox Technologies LTD. All rights reserved.
-  *
-  * This software is available to you under the OpenIB.org BSD license
-  * below:
-@@ -49,6 +50,8 @@
- #define src_out     data[0]
-+#define IB_LID_MCAST_START 0xc000
-+
- #define MAX_EP_ADDR 4
- #define MAX_EP_MC   2
-@@ -74,6 +77,11 @@ enum acm_loopback_prot {
-       ACM_LOOPBACK_PROT_LOCAL
- };
-+enum acm_path_rec_fmt {
-+      ACM_PATH_REV_FMT_NONE,
-+      ACM_PATH_REV_FMT_OSM_FULL_V1
-+};
-+
- /*
-  * Nested locking order: dest -> ep, dest -> port
-  */
-@@ -210,6 +218,7 @@ static atomic_t counter[ACM_MAX_COUNTER];
- static char *acme = BINDIR "/ib_acme -A";
- static char *opts_file = ACM_CONF_DIR "/" ACM_OPTS_FILE;
- static char *addr_file = ACM_CONF_DIR "/" ACM_ADDR_FILE;
-+static char path_rec_file[128] = ACM_CONF_DIR "/" ACM_PATH_REC_FILE;
- static char log_file[128] = "/var/log/ibacm.log";
- static int log_level = 0;
- static char lock_file[128] = "/var/run/ibacm.pid";
-@@ -227,6 +236,7 @@ static int send_depth = 1;
- static int recv_depth = 1024;
- static uint8_t min_mtu = IBV_MTU_2048;
- static uint8_t min_rate = IBV_RATE_10_GBPS;
-+static enum acm_path_rec_fmt path_rec_fmt = ACM_PATH_REV_FMT_NONE;
- #define acm_log(level, format, ...) \
-       acm_write(level, "%s: "format, __func__, ## __VA_ARGS__)
-@@ -2444,6 +2454,15 @@ static enum acm_loopback_prot acm_convert_loopback_prot(char *param)
-       return loopback_prot;
- }
-+static enum acm_path_rec_fmt acm_convert_path_rec_fmt(char *param)
-+{
-+      if (!stricmp("none", param))
-+              return ACM_PATH_REV_FMT_NONE;
-+      else if (!stricmp("full_opensm_v1", param))
-+              return ACM_PATH_REV_FMT_OSM_FULL_V1;
-+      return path_rec_fmt;
-+}
-+
- static enum ibv_rate acm_get_rate(uint8_t width, uint8_t speed)
- {
-       switch (width) {
-@@ -2553,6 +2572,224 @@ static FILE *acm_open_addr_file(void)
-       return fopen(addr_file, "r");
- }
-+static void acm_parse_path_records_pass1(FILE *f, uint64_t *lid2guid)
-+{
-+      char s[128];
-+      char *p, *ptr, *p_guid, *p_lid;
-+      uint64_t guid;
-+      uint16_t lid;
-+
-+      /* Pass 1 - LID to GUID table */
-+      while (fgets(s, sizeof s, f)) {
-+              if (s[0] == '#')
-+                      continue;
-+              if (!(p = strtok_r(s, " \n", &ptr)))
-+                      continue;       /* ignore blank lines */
-+
-+              if (strncmp(p, "Switch", sizeof("Switch") - 1) &&
-+                  strncmp(p, "Channel", sizeof("Channel") - 1) &&
-+                  strncmp(p, "Router", sizeof("Router") - 1))
-+                      continue;
-+
-+              if (!strncmp(p, "Channel", sizeof("Channel") - 1)) {
-+                      p = strtok_r(NULL, " ", &ptr); /* skip 'Adapter' */
-+                      if (!p)
-+                              continue;
-+              }
-+
-+              p_guid = strtok_r(NULL, ",", &ptr);
-+              if (!p_guid)
-+                      continue;
-+
-+              guid = (uint64_t) strtoull(p_guid, NULL, 16);
-+
-+              ptr = strstr(ptr, "base LID");
-+              if (!ptr)
-+                      continue;
-+              ptr += sizeof("base LID");
-+              p_lid = strtok_r(NULL, ",", &ptr);
-+              if (!p_lid)
-+                      continue;
-+
-+              lid = (uint16_t) strtoul(p_lid, NULL, 0);
-+              if (lid >= IB_LID_MCAST_START)
-+                      continue;
-+              if (lid2guid[lid])
-+                      acm_log(0, "ERROR - duplicate lid %u\n", lid);
-+              else
-+                      lid2guid[lid] = htonll(guid);
-+      }
-+}
-+
-+static int acm_parse_path_records_pass2(FILE *f, uint64_t *lid2guid,
-+                                      struct acm_ep *ep)
-+{
-+      union ibv_gid sgid, dgid;
-+      struct ibv_port_attr attr = { 0 };
-+      struct acm_dest *dest;
-+      char s[128];
-+      char *p, *ptr, *p_guid, *p_lid;
-+      uint64_t guid;
-+      uint16_t lid, dlid;
-+      int sl, mtu, rate;
-+      int ret = 1, i;
-+      uint8_t addr[ACM_MAX_ADDRESS];
-+      uint8_t addr_type;
-+
-+      ibv_query_gid(ep->port->dev->verbs, ep->port->port_num, 0, &sgid);
-+
-+      /* Pass 2 - Path records for source to all destinations */
-+
-+      while (fgets(s, sizeof s, f)) {
-+              if (s[0] == '#')
-+                      continue;
-+              if (!(p = strtok_r(s, " \n", &ptr)))
-+                      continue;       /* ignore blank lines */
-+
-+              if (strncmp(p, "Switch", sizeof("Switch") - 1) &&
-+                  strncmp(p, "Channel", sizeof("Channel") - 1) &&
-+                  strncmp(p, "Router", sizeof("Router") - 1))
-+                      continue;
-+
-+              if (!strncmp(p, "Channel", sizeof("Channel") - 1)) {
-+                      p = strtok_r(NULL, " ", &ptr); /* skip 'Adapter' */
-+                      if (!p)
-+                              continue;
-+              }
-+
-+              p_guid = strtok_r(NULL, ",", &ptr);
-+              if (!p_guid)
-+                      continue;
-+
-+              guid = (uint64_t) strtoull(p_guid, NULL, 16);
-+              if (guid != ntohll(sgid.global.interface_id))
-+                      continue;
-+
-+              ptr = strstr(ptr, "base LID");
-+              if (!ptr)
-+                      continue;
-+              ptr += sizeof("base LID");
-+              p_lid = strtok_r(NULL, ",", &ptr);
-+              if (!p_lid)
-+                      continue;
-+
-+              lid = (uint16_t) strtoul(p_lid, NULL, 0);
-+              if (lid != ep->port->lid)
-+                      continue;
-+              ibv_query_port(ep->port->dev->verbs, ep->port->port_num, &attr);
-+              ret = 0;
-+              break;
-+      }
-+
-+      while (fgets(s, sizeof s, f)) {
-+              if (s[0] == '#')
-+                      continue;
-+              if (!(p = strtok_r(s, " \n", &ptr)))
-+                      continue;       /* ignore blank lines */
-+
-+              if (!strncmp(p, "Switch", sizeof("Switch") - 1) ||
-+                  !strncmp(p, "Channel", sizeof("Channel") - 1) ||
-+                  !strncmp(p, "Router", sizeof("Router") - 1))
-+                      break;
-+
-+              dlid = strtoul(p, NULL, 0);
-+
-+              p = strtok_r(NULL, ":", &ptr);
-+              if (!p)
-+                      continue;
-+              if (strcmp(p, "UNREACHABLE") == 0)
-+                      continue;
-+              sl = atoi(p);
-+
-+              p = strtok_r(NULL, ":", &ptr);
-+              if (!p)
-+                      continue;
-+              mtu = atoi(p);
-+
-+              p = strtok_r(NULL, ":", &ptr);
-+              if (!p)
-+                      continue;
-+              rate = atoi(p);
-+
-+              if (!lid2guid[dlid]) {
-+                      acm_log(0, "ERROR - dlid %u not found in lid2guid table\n", dlid);
-+                      continue;
-+              }
-+
-+              dgid.global.subnet_prefix = sgid.global.subnet_prefix;
-+              dgid.global.interface_id = lid2guid[dlid];
-+
-+              for (i = 0; i < 2; i++) {
-+                      memset(addr, 0, ACM_MAX_ADDRESS);
-+                      if (i == 0) {
-+                              addr_type = ACM_ADDRESS_LID;
-+                              *((uint16_t *) addr) = htons(dlid);
-+                      } else {
-+                              addr_type = ACM_ADDRESS_GID;
-+                              memcpy(addr, &dgid, sizeof(dgid));
-+                      }
-+                      dest = acm_acquire_dest(ep, addr_type, addr);
-+                      if (!dest) {
-+                              acm_log(0, "ERROR - unable to create dest\n");
-+                              break;
-+                      }
-+
-+                      dest->path.sgid = sgid;
-+                      dest->path.slid = htons(ep->port->lid);
-+                      dest->path.dgid = dgid;
-+                      dest->path.dlid = htons(dlid);
-+                      dest->path.reversible_numpath = IBV_PATH_RECORD_REVERSIBLE;
-+                      dest->path.pkey = htons(ep->pkey);
-+                      dest->path.mtu = (uint8_t) mtu;
-+                      dest->path.rate = (uint8_t) rate;
-+                      dest->path.qosclass_sl = htons((uint16_t) sl & 0xF);
-+                      if (dlid == ep->port->lid) {
-+                              dest->path.packetlifetime = 0;
-+                              dest->addr_timeout = (uint64_t)~0ULL;
-+                              dest->route_timeout = (uint64_t)~0ULL;
-+                      } else {
-+                              dest->path.packetlifetime = attr.subnet_timeout;
-+                              dest->addr_timeout = time_stamp_min() + (unsigned) addr_timeout;
-+                              dest->route_timeout = time_stamp_min() + (unsigned) route_timeout;
-+                      }
-+                      dest->remote_qpn = 1;
-+                      dest->state = ACM_READY;
-+                      acm_put_dest(dest);
-+                      acm_log(1, "added cached dest %s\n", dest->name);
-+              }
-+      }
-+      return ret;
-+}
-+
-+static int acm_parse_path_records(struct acm_ep *ep)
-+{
-+      FILE *f;
-+      uint64_t *lid2guid;
-+      int ret = 1;
-+
-+      if (!(f = fopen(path_rec_file, "r"))) {
-+              acm_log(0, "ERROR - couldn't open %s\n", path_rec_file);
-+              return ret;
-+      }
-+
-+      lid2guid = calloc(IB_LID_MCAST_START, sizeof(*lid2guid));
-+      if (!lid2guid) {
-+              acm_log(0, "ERROR - no memory for path record parsing\n");
-+              goto err;
-+      }
-+
-+      if (path_rec_fmt == ACM_PATH_REV_FMT_OSM_FULL_V1) {
-+              acm_parse_path_records_pass1(f, lid2guid);
-+              rewind(f);
-+              ret = acm_parse_path_records_pass2(f, lid2guid, ep);
-+      }
-+
-+      free(lid2guid);
-+err:
-+      fclose(f);
-+      return ret;
-+}
-+
- static int acm_assign_ep_names(struct acm_ep *ep)
- {
-       FILE *faddr;
-@@ -2802,6 +3039,13 @@ static void acm_ep_up(struct acm_port *port, uint16_t pkey_index)
-       lock_acquire(&port->lock);
-       DListInsertHead(&ep->entry, &port->ep_list);
-       lock_release(&port->lock);
-+
-+      if (path_rec_fmt == ACM_PATH_REV_FMT_OSM_FULL_V1) {
-+              ret = acm_parse_path_records(ep);
-+              if (ret)
-+                      acm_log(1, "unable to find ep in path records\n");
-+      }
-+
-       return;
- err2:
-@@ -3114,6 +3358,10 @@ static void acm_set_options(void)
-                       min_mtu = acm_convert_mtu(atoi(value));
-               else if (!stricmp("min_rate", opt))
-                       min_rate = acm_convert_rate(atoi(value));
-+              else if (!stricmp("path_rec_fmt", opt))
-+                      path_rec_fmt = acm_convert_path_rec_fmt(value);
-+              else if (!stricmp("path_rec_file", opt))
-+                      strcpy(path_rec_file, value);
-       }
-       fclose(f);
-@@ -3137,6 +3385,8 @@ static void acm_log_options(void)
-       acm_log(0, "receive depth %d\n", recv_depth);
-       acm_log(0, "minimum mtu %d\n", min_mtu);
-       acm_log(0, "minimum rate %d\n", min_rate);
-+      acm_log(0, "path record format %d\n", path_rec_fmt);
-+      acm_log(0, "path record file %s\n", path_rec_file);
- }
- static FILE *acm_open_log(void)
-@@ -3200,9 +3450,9 @@ static void show_usage(char *program)
-       printf("   [-D]             - run as a daemon (default)\n");
-       printf("   [-P]             - run as a standard process\n");
-       printf("   [-A addr_file]   - address configuration file\n");
--      printf("                      (default %s/%s\n", ACM_CONF_DIR, ACM_ADDR_FILE);
-+      printf("                      (default %s/%s)\n", ACM_CONF_DIR, ACM_ADDR_FILE);
-       printf("   [-O option_file] - option configuration file\n");
--      printf("                      (default %s/%s\n", ACM_CONF_DIR, ACM_OPTS_FILE);
-+      printf("                      (default %s/%s)\n", ACM_CONF_DIR, ACM_OPTS_FILE);
- }
- int CDECL_FUNC main(int argc, char **argv)
-diff --git a/src/acme.c b/src/acme.c
-index 1abb644..7c87aa1 100644
---- a/src/acme.c
-+++ b/src/acme.c
-@@ -244,6 +244,18 @@ static void gen_opts_temp(FILE *f)
-       fprintf(f, "\n");
-       fprintf(f, "min_rate 10\n");
-       fprintf(f, "\n");
-+      fprintf(f, "# path_rec_fmt:\n");
-+      fprintf(f, "# Indicates format of optional path records file for preloading ACM cache.\n");
-+      fprintf(f, "# Supported formats are:\n");
-+      fprintf(f, "# none - No path record file preloading (default)\n");
-+      fprintf(f, "# full_opensm_v1 - OpenSM \"full\" path records dump file format (version 1)\n");
-+      fprintf(f, "\n");
-+      fprintf(f, "path_rec_fmt none\n");
-+      fprintf(f, "\n");
-+      fprintf(f, "# path_rec_file:\n");
-+      fprintf(f, "# If path_rec_fmt is other than \"none\", full pathname of path records file\n");
-+      fprintf(f, "# to use for preloading the ACM cache.  Default is ACM_CONF_DIR/ibacm_path_records.dump\n");
-+      fprintf(f, "\n");
- }
- static int open_dir(void)