DABC (Data Acquisition Backbone Core)  2.9.9
Context.cxx
Go to the documentation of this file.
1 /************************************************************
2  * The Data Acquisition Backbone Core (DABC) *
3  ************************************************************
4  * Copyright (C) 2009 - *
5  * GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
6  * Planckstr. 1, 64291 Darmstadt, Germany *
7  * Contact: http://dabc.gsi.de *
8  ************************************************************
9  * This software can be used under the GPL license *
10  * agreements as stated in LICENSE.txt file *
11  * which is part of the distribution. *
12  ************************************************************/
13 
14 #include "verbs/Context.h"
15 
16 #include <sys/poll.h>
17 #include <cerrno>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <unistd.h>
21 #include <cstring>
22 #include <netinet/in.h>
23 #include <endian.h>
24 
25 
26 #ifndef __NO_MULTICAST__
27 #include "verbs/OpenSM.h"
28 #endif
29 
30 
31 #include "dabc/timing.h"
32 #include "dabc/logging.h"
33 #include "dabc/Manager.h"
34 
35 
36 const char* verbs::typeThread = "verbs::Thread";
37 const char* verbs::typeDevice = "verbs::Device";
38 
39 
40 int null_gid(union ibv_gid *gid)
41 {
42  return !(gid->raw[8] | gid->raw[9] | gid->raw[10] | gid->raw[11] |
43  gid->raw[12] | gid->raw[13] | gid->raw[14] | gid->raw[15]);
44 }
45 
46 
47 // *******************************************************************
48 
50  dabc::Object(0, pool->GetName()),
51  fContext(ctx),
52  fPool(pool),
53  fLastChangeCounter(0),
54  f_nummr(0),
55  f_mr(0)
56 {
57  DOUT4("Create registry for the POOL: %s numref %u", GetName(), NumReferences());
58 }
59 
61 {
62  DOUT4("~PoolRegistry %s refs %u", GetName(), NumReferences());
63 
64  CleanMRStructure();
65 
66  DOUT4("~PoolRegistry %s refs %u done", GetName(), NumReferences());
67 }
68 
70 {
71  // TODO: later one can enable this code to get info when pool destroyed too early
72  // if (dabc::mgr() && fPool)
73  // dabc::mgr()->UnregisterDependency(this, fPool);
74 
76 }
77 
79 {
80  if (obj == fPool) {
81  EOUT("!!!!!!!!! Hard error - memory pool %s destroyed behind the scene", fPool->GetName());
82  CleanMRStructure();
83  fPool = 0;
84  DeleteThis();
85  }
86 }
87 
89 {
90  DOUT3("CleanMRStructure %s call ibv_dereg_mr %u", GetName(), f_nummr);
91 
92  for (unsigned n=0;n<f_nummr;n++)
93  if (f_mr[n] != 0) {
94  DOUT5("CleanMRStructure %s mr[%u] = %p", GetName(), n, f_mr[n]);
95 // if (strcmp(GetName(),"TransportPool")!=0)
96  ibv_dereg_mr(f_mr[n]);
97 // else
98 // EOUT("Skip ibv_dereg_mr(f_mr[n])");
99  DOUT5("CleanMRStructure %s mr[%u] = %p done", GetName(), n, f_mr[n]);
100  }
101 
102  delete[] f_mr;
103  f_mr = 0;
104  f_nummr = 0;
105 
106 // fLastChangeCounter = 0;
107 }
108 
109 
111 {
112  if (fPool==0) return;
113 
114  DOUT5("CreateMRStructure %s for pool %p numrefs %u", GetName(), fPool, NumReferences());
115 
116  std::vector<void*> bufs;
117  std::vector<unsigned> sizes;
118 
119  // we perform complete synchronization under pool mutex that concurrent thread do not disturb each other
120 
121  // FIXME: in current implementation pool is fixed-layout therefore first transport will produce
122  // correct structure which should not be changed until the end
123  // but this method cannot be used to update structure if pool changes in between
124 
125  {
126 
127  dabc::LockGuard lock(fPool->GetPoolMutex());
128 
129  if (!fPool->_GetPoolInfo(bufs, sizes, &fLastChangeCounter)) return;
130 
131  if (f_nummr!=0) CleanMRStructure();
132 
133  DOUT5("CreateMRStructure %p for pool %p size %u", this, fPool, bufs.size());
134 
135  f_nummr = bufs.size();
136 
137  f_mr = new struct ibv_mr* [f_nummr];
138 
139  for (unsigned n=0;n<f_nummr;n++) {
140 
141  f_mr[n] = ibv_reg_mr(fContext.pd(), bufs[n], sizes[n],
142  (ibv_access_flags) (IBV_ACCESS_REMOTE_WRITE | IBV_ACCESS_LOCAL_WRITE));
143 
144  DOUT5("CreateMRStructure %p for pool %p mr[%u] = %p done", this, fPool, n, f_mr[n]);
145 
146  if (f_mr[n]==0) {
147  EOUT("Fail to register VERBS memory - HALT");
148  exit(138);
149  }
150  }
151  }
152 
153  DOUT5("CreateMRStructure %p for pool %p size %u done", this, fPool, bufs.size());
154 
155  // TODO: later one can enable this code to get
156 
157 // if (dabc::mgr() && fPool)
158 // dabc::mgr()->RegisterDependency(this, fPool);
159 }
160 
161 // _________________________________________________________________________
162 
164  dabc::Object(0, "VERBS"),
165  fIbPort(0),
166  fContext(0),
167  fPD(0),
168  fOsm(0)
169 {
170 }
171 
172 
174 {
175  CloseVerbs();
176 
177  DOUT0("VERBS Context destroyed");
178 }
179 
180 
181 
182 bool verbs::Context::OpenVerbs(bool withmulticast, const char* devicename, int ibport)
183 {
184  DOUT1("Call verbs::Context::OpenVerbs multicast=%s", DBOOL(withmulticast));
185 
186 #ifndef __NO_MULTICAST__
187  if (withmulticast) {
188  fOsm = new OpenSM;
189  if (!fOsm->Init()) return false;
190  }
191 #endif
192 
193  int num_of_hcas = 0;
194 
195  struct ibv_device **dev_list = ibv_get_device_list(&num_of_hcas);
196 
197  if ((dev_list==0) || (num_of_hcas<=0)) {
198  EOUT("No verbs devices found");
199  return false;
200  }
201 
202  DOUT1( "Number of hcas %d", num_of_hcas);
203 
204  struct ibv_device *selected_device = 0;
205  uint64_t gid;
206  bool res = false;
207 
208  if (devicename==0) {
209  selected_device = dev_list[0];
210  fIbPort = 1;
211  devicename = ibv_get_device_name(selected_device);
212  } else {
213  fIbPort = ibport;
214  if (fIbPort<=0) fIbPort = 1;
215  for (int n=0;n<num_of_hcas;n++)
216  if (strcmp(ibv_get_device_name(dev_list[n]), devicename)==0)
217  selected_device = dev_list[n];
218  if (selected_device==0) {
219  EOUT("No verbs device with name %s", devicename);
220  }
221  }
222 
223  if (selected_device==0) goto cleanup;
224 
225  fContext = ibv_open_device(selected_device);
226  if (fContext==0) {
227  EOUT("Cannot open device %s", devicename);
228  goto cleanup;
229  }
230 
231  if (ibv_query_device(fContext, &fDeviceAttr)) {
232  EOUT("Failed to query device props");
233  goto cleanup;
234  }
235 
236  gid = ibv_get_device_guid(selected_device);
237  DOUT1( "Open device: %s gid: %016lx", devicename, be64toh(gid));
238 
239  fPD = ibv_alloc_pd(fContext);
240  if (fPD==0) {
241  EOUT("Couldn't allocate protection domain (PD)");
242  goto cleanup;
243  }
244 
245  if (ibv_query_port(fContext, fIbPort, &fPortAttr)) {
246  EOUT("Fail to query port attributes");
247  goto cleanup;
248  }
249 
250 // PrintDevicesList(true);
251 
252  DOUT1("verbs::Context::OpenVerbs done");
253 
254  res = true;
255 
256 cleanup:
257 
258  ibv_free_device_list(dev_list);
259 
260  return res;
261 
262 }
263 
265 {
266  if (fContext==0) return true;
267 
268  bool res = true;
269 
270  if (ibv_dealloc_pd(fPD)) {
271  EOUT("Fail to deallocate PD");
272  res = false;
273  }
274  if (ibv_close_device(fContext)) {
275  EOUT("Fail to close device context");
276  res = false;
277  }
278 
279  fPD = 0;
280  fContext = 0;
281 
282 #ifndef __NO_MULTICAST__
283  if (fOsm!=0) {
284  fOsm->Close();
285  delete fOsm;
286  fOsm = 0;
287  }
288 #endif
289 
290  return res;
291 }
292 
293 
294 bool verbs::ContextRef::OpenVerbs(bool withmulticast, const char* devicename, int ibport)
295 {
296  if (GetObject()) return true;
297 
298  DOUT1("Creating new context object");
299 
300  Context* ctx = new Context;
301  ctx->SetAutoDestroy(true);
302 
303  DOUT1("Creating new context done");
304 
305  if (!ctx->OpenVerbs(withmulticast, devicename, ibport)) {
306  delete ctx;
307  return false;
308  }
309 
310  SetObject(ctx);
311  SetAutoDestroy(true);
312  return true;
313 }
314 
315 
316 int verbs::ContextRef::ManageMulticast(int action, ibv_gid& mgid, uint16_t& mlid)
317 {
318  // Use MulticastActions for
319  // action = mcst_Error - do nothing return mcst_Error
320  // action = mcst_Ok - do nothing return mcst_Ok
321  // action = mcst_Register - register, return mcst_Unregister/mcst_Error
322  // action = mcst_Query - query return mcst_Ok/mcst_Error
323  // action = mcst_Init - query or reg return mcst_Ok/mcst_Unregister/mcst_Error
324  // action = mcst_Unregister - unreg return mcst_Ok/mcst_Error
325 
326 #ifndef __NO_MULTICAST__
327 
328  OpenSM osm = GetObject() ? GetObject()->fOsm : 0;
329 
330  if (osm==0) return 0;
331  switch (action) {
332  case mcst_Error: return mcst_Error;
333  case mcst_Ok: return mcst_Ok;
334  case mcst_Register:
335  mlid = 0;
336  if (osm->ManageMultiCastGroup(true, mgid.raw, &mlid)) return mcst_Unregister;
337  return mcst_Error;
338  case mcst_Query:
339  mlid = 0;
340  if (osm->QueryMyltucastGroup(mgid.raw, mlid)) return mcst_Ok;
341  return mcst_Error;
342  case mcst_Init:
343  mlid = 0;
344  if (osm->QueryMyltucastGroup(mgid.raw, mlid))
345  if (mlid!=0) return mcst_Ok;
346  if (osm->ManageMultiCastGroup(true, mgid.raw, &mlid)) return mcst_Unregister;
347  return mcst_Error;
348  case mcst_Unregister:
349  if (osm->ManageMultiCastGroup(false, mgid.raw, &mlid)) return mcst_Ok;
350  return mcst_Error;
351  }
352 #endif
353 
354  return mcst_Error;
355 }
356 
357 struct ibv_ah* verbs::ContextRef::CreateAH(uint32_t dest_lid)
358 {
359  ibv_ah_attr ah_attr;
360  memset(&ah_attr, 0, sizeof(ah_attr));
361  ah_attr.is_global = 0;
362  ah_attr.dlid = dest_lid;
363  ah_attr.sl = 0;
364  ah_attr.src_path_bits = 0;
365  ah_attr.port_num = IbPort(); // !!!!!!! probably, here should be destination port
366 
367  ibv_ah *ah = ibv_create_ah(pd(), &ah_attr);
368  if (ah==0) {
369  EOUT("Failed to create Address Handle");
370  }
371  return ah;
372 }
373 
374 struct ibv_ah* verbs::ContextRef::CreateMAH(ibv_gid& mgid, uint32_t mlid)
375 {
376  ibv_ah_attr mah_attr;
377  memset(&mah_attr, 0, sizeof(ibv_ah_attr));
378 
379  mah_attr.dlid = mlid; // in host order ?
380  mah_attr.port_num = IbPort();
381  mah_attr.sl = 0;
382  mah_attr.static_rate = 0; //0x83; // should be copied from member rec
383 
384  mah_attr.is_global = 1;
385  memcpy(&(mah_attr.grh.dgid), &mgid, sizeof(ibv_gid));
386  mah_attr.grh.sgid_index = 0; // GetGidIndex(mgid);
387 
388  mah_attr.grh.flow_label = 0; // should be copied from member rec
389  mah_attr.grh.hop_limit = 63; // should be copied from member rec
390  mah_attr.grh.traffic_class = 0; // should be copied from member rec
391 
392  //DOUT1("Addr %02x %02x", ah_attr.grh.dgid.raw[0], ah_attr.grh.dgid.raw[1]);
393 
394  struct ibv_ah* f_ah = ibv_create_ah(pd(), &mah_attr);
395  if (f_ah==0) {
396  EOUT("Failed to create Multicast Address Handle");
397  }
398 
399  return f_ah;
400 }
401 
402 
404 {
405  if (pool==0) return 0;
406 
407  dabc::Reference folder = GetFolder("PoolReg", true);
408 
409  folder.RemoveChild(pool->GetName(), true);
410 
411  PoolRegistryRef ref = new PoolRegistry(*this, pool);
412 
413  if (ref.null()) {
414  EOUT("Error - cannot create pool registry object for pool %s", pool->GetName());
415  return 0;
416  }
417 
418  folder.AddChild(ref.GetObject());
419 
420  if (ref()->GetPool() != pool) {
421  EOUT("Registry entry for name %s exists but pool pointer mismatch", pool->GetName());
422 
423  exit(543);
424  }
425 
426  ref()->SyncMRStructure();
427 
428  return ref;
429 }
430 
431 int verbs::ContextRef::GetGidIndex(ibv_gid* lookgid)
432 {
433  ibv_gid gid;
434  int ret = 0;
435 
436  DOUT5( "Search for gid in table: %016lx : %016lx ",
437  be64toh(lookgid->global.subnet_prefix),
438  be64toh(lookgid->global.interface_id));
439 
440  for (int i = 0; !ret; i++) {
441  ret = ibv_query_gid(context(), IbPort(), i, &gid);
442 
443  if (ret) break;
444 
445  if (null_gid(&gid)) continue;
446 
447  DOUT5(" gid[%2d]: %016lx : %016lx ", i,
448  be64toh(gid.global.subnet_prefix),
449  be64toh(gid.global.interface_id));
450 
451  // deepcode ignore RiskyMemoryManipulation: false positive
452  if (!ret && !memcmp(lookgid, &gid, sizeof(ibv_gid))) return i;
453  }
454  return 0;
455 }
456 
int null_gid(union ibv_gid *gid)
Definition: Context.cxx:40
Lock guard for posix mutex.
Definition: threads.h:127
Base class for most of the DABC classes.
Definition: Object.h:116
unsigned NumReferences()
Return number of references on the object.
Definition: Object.cxx:557
const char * GetName() const
Returns name of the object, thread safe
Definition: Object.h:295
void SetAutoDestroy(bool on=true)
Set autodestroy flag for the object Once enabled, object will be destroyed when last reference will b...
Definition: Object.cxx:160
virtual void ObjectCleanup()
User method to cleanup object content before it will be destroyed Main motivation is to release any r...
Definition: Object.cxx:532
Reference on the arbitrary object
Definition: Reference.h:73
bool AddChild(Object *obj)
Add child to list of object children.
Definition: Reference.cxx:188
Object * GetObject() const
Return pointer on the object.
Definition: Reference.h:129
bool RemoveChild(const char *name, bool cleanup=true)
Remove child with given name and return reference on that child.
Definition: Reference.cxx:215
bool null() const
Returns true if reference contains nullptr.
Definition: Reference.h:151
Reference to verbs::Context
Definition: Context.h:74
struct ibv_ah * CreateAH(uint32_t dest_lid)
Definition: Context.cxx:357
dabc::Reference RegisterPool(dabc::MemoryPool *pool)
Definition: Context.cxx:403
bool OpenVerbs(bool withmulticast=false, const char *devicename=0, int ibport=-1)
Definition: Context.cxx:294
struct ibv_ah * CreateMAH(ibv_gid &mgid, uint32_t mlid)
Definition: Context.cxx:374
int ManageMulticast(int action, ibv_gid &mgid, uint16_t &mlid)
Definition: Context.cxx:316
int GetGidIndex(ibv_gid *lookgid)
Definition: Context.cxx:431
Context for all VERBS operations.
Definition: Context.h:43
virtual ~Context()
Definition: Context.cxx:173
bool CloseVerbs()
Definition: Context.cxx:264
bool OpenVerbs(bool withmulticast=false, const char *devicename=0, int ibport=-1)
Definition: Context.cxx:182
Interface class to opensm.
Definition: OpenSM.h:28
bool QueryMyltucastGroup(uint8_t *mgid, uint16_t &mlid)
Definition: OpenSM.cxx:425
bool ManageMultiCastGroup(bool isadd, uint8_t *mgid, uint16_t *mlid)
Definition: OpenSM.cxx:253
Reference on verbs::PoolRegistry
Definition: Context.h:143
Registry object for memory pool.
Definition: Context.h:106
PoolRegistry(ContextRef ctx, dabc::MemoryPool *pool)
Definition: Context.cxx:49
virtual ~PoolRegistry()
Definition: Context.cxx:60
virtual void ObjectDestroyed(dabc::Object *obj)
Method called by the manager when registered dependent object is destroyed Should be used in user cla...
Definition: Context.cxx:78
virtual void ObjectCleanup()
User method to cleanup object content before it will be destroyed Main motivation is to release any r...
Definition: Context.cxx:69
void CleanMRStructure()
Definition: Context.cxx:88
void SyncMRStructure()
Definition: Context.cxx:110
#define DOUT0(args ...)
Definition: logging.h:156
#define DOUT5(args ...)
Definition: logging.h:188
#define DOUT3(args ...)
Definition: logging.h:176
#define EOUT(args ...)
Definition: logging.h:150
#define DOUT1(args ...)
Definition: logging.h:162
#define DBOOL(arg)
Definition: logging.h:191
#define DOUT4(args ...)
Definition: logging.h:182
Event manipulation API.
Definition: api.h:23
const char * typeThread
Definition: Context.cxx:36
const char * typeDevice
Definition: Context.cxx:37