FD.io VPP  v16.09
Vector Packet Processing
svmdb.c
Go to the documentation of this file.
1 /*
2  *------------------------------------------------------------------
3  * svmdb.c -- simple shared memory database
4  *
5  * Copyright (c) 2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/mman.h>
24 #include <sys/stat.h>
25 #include <netinet/in.h>
26 #include <signal.h>
27 #include <pthread.h>
28 #include <unistd.h>
29 #include <time.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <vppinfra/clib.h>
33 #include <vppinfra/vec.h>
34 #include <vppinfra/hash.h>
35 #include <vppinfra/bitmap.h>
36 #include <vppinfra/fifo.h>
37 #include <vppinfra/time.h>
38 #include <vppinfra/mheap.h>
39 #include <vppinfra/heap.h>
40 #include <vppinfra/pool.h>
41 #include <vppinfra/format.h>
42 
43 #include "svmdb.h"
44 
45 static void local_set_variable_nolock (svmdb_client_t * client,
46  svmdb_namespace_t namespace,
47  u8 * var, u8 * val, u32 elsize);
48 
49 always_inline void
50 region_lock (svm_region_t * rp, int tag)
51 {
52  pthread_mutex_lock (&rp->mutex);
53 #ifdef MUTEX_DEBUG
54  rp->mutex_owner_pid = getpid ();
55  rp->mutex_owner_tag = tag;
56 #endif
57 }
58 
59 always_inline void
61 {
62 #ifdef MUTEX_DEBUG
63  rp->mutex_owner_pid = 0;
64  rp->mutex_owner_tag = 0;
65 #endif
66  pthread_mutex_unlock (&rp->mutex);
67 }
68 
71 {
72  svmdb_client_t *client = 0;
74  svm_region_t *db_rp;
75  void *oldheap;
76  svmdb_shm_hdr_t *hp = 0;
77 
78  vec_validate (client, 0);
79  vec_validate (a, 0);
80 
82 
83  a->root_path = dba->root_path;
84  a->name = "/db";
85  a->size = dba->size ? dba->size : SVMDB_DEFAULT_SIZE;
87  a->uid = dba->uid;
88  a->gid = dba->gid;
89 
90  db_rp = client->db_rp = svm_region_find_or_create (a);
91 
92  ASSERT (db_rp);
93 
94  vec_free (a);
95 
96  region_lock (client->db_rp, 10);
97  /* Has someone else set up the shared-memory variable table? */
98  if (db_rp->user_ctx)
99  {
100  client->shm = (void *) db_rp->user_ctx;
101  client->pid = getpid ();
102  region_unlock (client->db_rp);
103  ASSERT (client->shm->version == SVMDB_SHM_VERSION);
104  return (client);
105  }
106  /* Nope, it's our problem... */
107 
108  /* Add a bogus client (pid=0) so the svm won't be deallocated */
109  oldheap = svm_push_pvt_heap (db_rp);
110  vec_add1 (client->db_rp->client_pids, 0);
111  svm_pop_heap (oldheap);
112 
113  oldheap = svm_push_data_heap (db_rp);
114 
115  vec_validate (hp, 0);
118  = hash_create_string (0, sizeof (uword));
120  = hash_create_string (0, sizeof (uword));
121 
122  db_rp->user_ctx = hp;
123  client->shm = hp;
124 
125  svm_pop_heap (oldheap);
126  region_unlock (client->db_rp);
127  client->pid = getpid ();
128 
129  return (client);
130 }
131 
132 void
134 {
135  ASSERT (client);
136 
137  if (!svm_get_root_rp ())
138  return;
139 
140  svm_region_unmap ((void *) client->db_rp);
141  svm_region_exit ();
142  vec_free (client);
143 }
144 
145 static void
147 {
148  int i;
149  int rv;
150  union sigval sv;
151  u32 value;
152  u32 *dead_registrations = 0;
153 
154  svmdb_notify_t *np;
155 
156  for (i = 0; i < vec_len (v->notifications); i++)
157  {
158  np = vec_elt_at_index (v->notifications, i);
159  if (np->action == a)
160  {
161  value = (np->action << 28) | (np->opaque);
162  sv.sival_ptr = (void *) (uword) value;
163  do
164  {
165  rv = 0;
166  if (sigqueue (np->pid, np->signum, sv) == 0)
167  break;
168  rv = errno;
169  }
170  while (rv == EAGAIN);
171  if (rv == 0)
172  continue;
173  vec_add1 (dead_registrations, i);
174  }
175  }
176 
177  for (i = 0; i < vec_len (dead_registrations); i++)
178  {
179  np = vec_elt_at_index (v->notifications, dead_registrations[i]);
180  clib_warning ("dead reg pid %d sig %d action %d opaque %x",
181  np->pid, np->signum, np->action, np->opaque);
182  vec_delete (v->notifications, 1, dead_registrations[i]);
183  }
184  vec_free (dead_registrations);
185 }
186 
187 int
190 {
191  uword *h;
192  void *oldheap;
193  hash_pair_t *hp;
194  svmdb_shm_hdr_t *shm;
195  u8 *dummy_value = 0;
196  svmdb_value_t *value;
197  svmdb_notify_t *np;
198  int i;
199  int rv = 0;
200 
201  ASSERT (a->elsize);
202 
203  region_lock (client->db_rp, 18);
204  shm = client->shm;
205  oldheap = svm_push_data_heap (client->db_rp);
206 
207  h = shm->namespaces[a->nspace];
208 
209  hp = hash_get_pair_mem (h, a->var);
210  if (hp == 0)
211  {
212  local_set_variable_nolock (client, a->nspace, (u8 *) a->var,
213  dummy_value, a->elsize);
214  /* might have moved */
215  h = shm->namespaces[a->nspace];
216  hp = hash_get_pair_mem (h, a->var);
217  ASSERT (hp);
218  }
219 
220  value = pool_elt_at_index (shm->values, hp->value[0]);
221 
222  for (i = 0; i < vec_len (value->notifications); i++)
223  {
224  np = vec_elt_at_index (value->notifications, i);
225  if ((np->pid == client->pid)
226  && (np->signum == a->signum)
227  && (np->action == a->action) && (np->opaque == a->opaque))
228  {
229  if (a->add_del == 0 /* delete */ )
230  {
231  vec_delete (value->notifications, 1, i);
232  goto out;
233  }
234  else
235  { /* add */
237  ("%s: ignore dup reg pid %d signum %d action %d opaque %x",
238  a->var, client->pid, a->signum, a->action, a->opaque);
239  rv = -2;
240  goto out;
241  }
242  }
243  }
244  if (a->add_del == 0)
245  {
246  rv = -3;
247  goto out;
248  }
249 
250  vec_add2 (value->notifications, np, 1);
251  np->pid = client->pid;
252  np->signum = a->signum;
253  np->action = a->action;
254  np->opaque = a->opaque;
255 
256 out:
257  svm_pop_heap (oldheap);
258  region_unlock (client->db_rp);
259  return rv;
260 }
261 
262 
263 static void
265  svmdb_namespace_t namespace, char *var)
266 {
267  uword *h;
268  svmdb_value_t *oldvalue;
269  hash_pair_t *hp;
270 
271  h = client->shm->namespaces[namespace];
272  hp = hash_get_pair_mem (h, var);
273  if (hp)
274  {
275  oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
276  if (vec_len (oldvalue->notifications))
277  notify_value (oldvalue, SVMDB_ACTION_UNSET);
278  /* zero length value means unset */
279  _vec_len (oldvalue->value) = 0;
280  }
281  client->shm->namespaces[namespace] = h;
282 }
283 
284 void
286 {
287  void *oldheap;
288 
289  region_lock (client->db_rp, 11);
290  oldheap = svm_push_data_heap (client->db_rp);
292  svm_pop_heap (oldheap);
293  region_unlock (client->db_rp);
294 }
295 
296 static void
298  svmdb_namespace_t namespace,
299  u8 * var, u8 * val, u32 elsize)
300 {
301  uword *h;
302  hash_pair_t *hp;
303  u8 *name;
304  svmdb_shm_hdr_t *shm;
305 
306  shm = client->shm;
307  h = shm->namespaces[namespace];
308  hp = hash_get_pair_mem (h, var);
309  if (hp)
310  {
311  svmdb_value_t *oldvalue;
312  oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
313  vec_alloc (oldvalue->value, vec_len (val) * elsize);
314  clib_memcpy (oldvalue->value, val, vec_len (val) * elsize);
315  _vec_len (oldvalue->value) = vec_len (val);
316  notify_value (oldvalue, SVMDB_ACTION_SET);
317  }
318  else
319  {
320  svmdb_value_t *newvalue;
321  pool_get (shm->values, newvalue);
322  memset (newvalue, 0, sizeof (*newvalue));
323  newvalue->elsize = elsize;
324  vec_alloc (newvalue->value, vec_len (val) * elsize);
325  clib_memcpy (newvalue->value, val, vec_len (val) * elsize);
326  _vec_len (newvalue->value) = vec_len (val);
327  name = format (0, "%s%c", var, 0);
328  hash_set_mem (h, name, newvalue - shm->values);
329  }
330  shm->namespaces[namespace] = h;
331 }
332 
333 void
335  char *var, char *val)
336 {
337  void *oldheap;
338 
339  region_lock (client->db_rp, 12);
340  oldheap = svm_push_data_heap (client->db_rp);
341 
343 
345  (u8 *) var, (u8 *) val, 1 /* elsize */ );
346  svm_pop_heap (oldheap);
347  region_unlock (client->db_rp);
348 }
349 
350 static u8 *
352  svmdb_namespace_t namespace, u8 * var)
353 {
354  uword *h;
355  uword *p;
356  svmdb_shm_hdr_t *shm;
357  svmdb_value_t *oldvalue;
358 
359  shm = client->shm;
360  h = shm->namespaces[namespace];
361  p = hash_get_mem (h, var);
362  if (p)
363  {
364  oldvalue = pool_elt_at_index (shm->values, p[0]);
365  notify_value (oldvalue, SVMDB_ACTION_GET);
366  return (oldvalue->value);
367  }
368  return 0;
369 }
370 
371 void *
373  svmdb_namespace_t namespace, char *var)
374 {
375  u8 *rv;
376 
377  region_lock (client->db_rp, 19);
378  rv = local_get_variable_nolock (client, namespace, (u8 *) var);
379  region_unlock (client->db_rp);
380  return (void *) rv;
381 }
382 
383 char *
385 {
386  u8 *rv = 0;
387 
388  region_lock (client->db_rp, 13);
389  rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_STRING, (u8 *) var);
390 
391  if (rv && vec_len (rv))
392  {
393  rv = format (0, "%s", rv);
394  vec_add1 (rv, 0);
395  }
396  region_unlock (client->db_rp);
397  return ((char *) rv);
398 }
399 
400 void
402 {
403  uword *h;
404  u8 *key;
405  u32 value;
406  svmdb_shm_hdr_t *shm = client->shm;
407 
408  region_lock (client->db_rp, 14);
409 
410  h = client->shm->namespaces[SVMDB_NAMESPACE_STRING];
411 
412  /* *INDENT-OFF* */
413  hash_foreach_mem(key, value, h,
414  ({
415  svmdb_value_t *v = pool_elt_at_index (shm->values, value);
416 
417  fformat(stdout, "%s: %s\n", key,
418  vec_len(v->value) ? v->value : (u8 *)"(nil)");
419  }));
420  /* *INDENT-ON* */
421  region_unlock (client->db_rp);
422 }
423 
424 void
426 {
427  void *oldheap;
428 
429  region_lock (client->db_rp, 15);
430  oldheap = svm_push_data_heap (client->db_rp);
432  svm_pop_heap (oldheap);
433  region_unlock (client->db_rp);
434 }
435 
436 void
438  char *var, void *val_arg, u32 elsize)
439 {
440  u8 *val = (u8 *) val_arg;
441  void *oldheap;
442 
443  region_lock (client->db_rp, 16);
444  oldheap = svm_push_data_heap (client->db_rp);
445 
448  val, elsize);
449 
450  svm_pop_heap (oldheap);
451  region_unlock (client->db_rp);
452 }
453 
454 void *
455 svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, u32 elsize)
456 {
457  u8 *rv = 0;
458  u8 *copy = 0;
459 
460  region_lock (client->db_rp, 17);
461 
462  rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
463 
464  if (rv && vec_len (rv))
465  {
466  /* Make a copy in process-local memory */
467  vec_alloc (copy, vec_len (rv) * elsize);
468  clib_memcpy (copy, rv, vec_len (rv) * elsize);
469  _vec_len (copy) = vec_len (rv);
470  region_unlock (client->db_rp);
471  return (copy);
472  }
473  region_unlock (client->db_rp);
474  return (0);
475 }
476 
477 void
479 {
480  uword *h;
481  u8 *key;
482  u32 value;
483  svmdb_shm_hdr_t *shm;
484 
485  region_lock (client->db_rp, 17);
486  shm = client->shm;
487 
488  h = client->shm->namespaces[SVMDB_NAMESPACE_VEC];
489 
490  /* *INDENT-OFF* */
491  hash_foreach_mem(key, value, h,
492  ({
493  svmdb_value_t *v = pool_elt_at_index (shm->values, value);
494  (void) fformat(stdout, "%s:\n %U (%.2f)\n", key,
496  vec_len(v->value)*v->elsize, ((f64 *)(v->value))[0]);
497  }));
498  /* *INDENT-ON* */
499 
500  region_unlock (client->db_rp);
501 }
502 
503 void *
505  char *var, u32 nbytes)
506 {
507  void *oldheap;
508  u8 *rv = 0;
509 
510  region_lock (client->db_rp, 18);
511  oldheap = svm_push_data_heap (client->db_rp);
512 
513  rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
514 
515  if (rv)
516  {
517  goto out;
518  }
519  else
520  {
521  uword *h;
522  u8 *name;
523  svmdb_shm_hdr_t *shm;
524  svmdb_value_t *newvalue;
525 
526  shm = client->shm;
528 
529  pool_get (shm->values, newvalue);
530  memset (newvalue, 0, sizeof (*newvalue));
531  newvalue->elsize = 1;
532  vec_alloc (newvalue->value, nbytes);
533  _vec_len (newvalue->value) = nbytes;
534  name = format (0, "%s%c", var, 0);
535  hash_set_mem (h, name, newvalue - shm->values);
537  rv = newvalue->value;
538  }
539 
540 out:
541  svm_pop_heap (oldheap);
542  region_unlock (client->db_rp);
543  return (rv);
544 }
545 
546 /*
547  * fd.io coding-style-patch-verification: ON
548  *
549  * Local Variables:
550  * eval: (c-set-style "gnu")
551  * End:
552  */
char * root_path
Definition: svm.h:72
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
svm_region_t * svm_get_root_rp(void)
Definition: svm.c:54
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
static void svm_pop_heap(void *oldheap)
Definition: svm.h:189
void * svmdb_local_get_variable_reference(svmdb_client_t *client, svmdb_namespace_t namespace, char *var)
Definition: svmdb.c:372
a
Definition: bitmap.h:516
#define SVMDB_SHM_VERSION
Definition: svmdb.h:63
void svmdb_local_dump_vecs(svmdb_client_t *client)
Definition: svmdb.c:478
Fixed length block allocator.
svmdb_namespace_t nspace
Definition: svmdb.h:76
void svmdb_local_unset_vec_variable(svmdb_client_t *client, char *var)
Definition: svmdb.c:425
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:521
int signum
Definition: svmdb.h:36
#define hash_set_mem(h, key, value)
Definition: hash.h:274
#define hash_get_pair_mem(h, key)
Definition: hash.h:271
char * root_path
Definition: svmdb.h:86
static void region_lock(svm_region_t *rp, int tag)
Definition: svmdb.c:50
u32 action
Definition: svmdb.h:37
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:200
#define vec_alloc(V, N)
Allocate space for N more elements (no header, unspecified alignment)
Definition: vec.h:239
uword version
Definition: svmdb.h:57
void svmdb_unmap(svmdb_client_t *client)
Definition: svmdb.c:133
#define SVM_FLAGS_MHEAP
Definition: svm.h:32
uword value[0]
Definition: hash.h:164
svmdb_namespace_t
Definition: svmdb.h:48
void svmdb_local_dump_strings(svmdb_client_t *client)
Definition: svmdb.c:401
static void * svm_push_data_heap(svm_region_t *rp)
Definition: svm.h:181
#define always_inline
Definition: clib.h:84
uword * client_pids
Definition: svm.h:59
uword * namespaces[SVMDB_N_NAMESPACES]
Definition: svmdb.h:60
void * svm_region_find_or_create(svm_map_region_args_t *a)
Definition: svm.c:839
volatile void * user_ctx
Definition: svm.h:52
char * name
Definition: svm.h:73
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u8 * format_hex_bytes(u8 *s, va_list *va)
Definition: std-formats.c:84
#define clib_warning(format, args...)
Definition: error.h:59
#define hash_create_string(elts, value_bytes)
Definition: hash.h:641
svmdb_shm_hdr_t * shm
Definition: svmdb.h:70
svmdb_action_t
Definition: svmdb.h:25
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:369
#define SVMDB_DEFAULT_SIZE
Definition: svmdb.h:96
char * svmdb_local_get_string_variable(svmdb_client_t *client, char *var)
Definition: svmdb.c:384
u32 elsize
Definition: svmdb.h:45
void svm_region_exit()
Definition: svm.c:1078
#define hash_foreach_mem(key_var, value_var, h, body)
Definition: hash.h:426
static void * svm_push_pvt_heap(svm_region_t *rp)
Definition: svm.h:173
svm_region_t * db_rp
Definition: svmdb.h:69
static void local_unset_variable_nolock(svmdb_client_t *client, svmdb_namespace_t namespace, char *var)
Definition: svmdb.c:264
static u8 * local_get_variable_nolock(svmdb_client_t *client, svmdb_namespace_t namespace, u8 *var)
Definition: svmdb.c:351
void * svmdb_local_find_or_add_vec_variable(svmdb_client_t *client, char *var, u32 nbytes)
Definition: svmdb.c:504
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
#define clib_memcpy(a, b, c)
Definition: string.h:63
void svm_region_init_chroot_uid_gid(char *root_path, int uid, int gid)
Definition: svm.c:816
void svmdb_local_set_vec_variable(svmdb_client_t *client, char *var, void *val_arg, u32 elsize)
Definition: svmdb.c:437
svmdb_notify_t * notifications
Definition: svmdb.h:44
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:745
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
Bitmaps built as vectors of machine words.
u32 opaque
Definition: svmdb.h:38
int svmdb_local_add_del_notification(svmdb_client_t *client, svmdb_notification_args_t *a)
Definition: svmdb.c:188
int mutex_owner_tag
Definition: svm.h:45
u64 uword
Definition: types.h:112
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
void svmdb_local_unset_string_variable(svmdb_client_t *client, char *var)
Definition: svmdb.c:285
static void local_set_variable_nolock(svmdb_client_t *client, svmdb_namespace_t namespace, u8 *var, u8 *val, u32 elsize)
Definition: svmdb.c:297
void svm_region_unmap(void *rp_arg)
Definition: svm.c:958
svmdb_client_t * svmdb_map(svmdb_map_args_t *dba)
Definition: svmdb.c:70
word fformat(FILE *f, char *fmt,...)
Definition: format.c:452
void * svmdb_local_get_vec_variable(svmdb_client_t *client, char *var, u32 elsize)
Definition: svmdb.c:455
#define hash_get_mem(h, key)
Definition: hash.h:268
u8 * value
Definition: svmdb.h:43
uword size
Definition: svmdb.h:87
svmdb_value_t * values
Definition: svmdb.h:59
void svmdb_local_set_string_variable(svmdb_client_t *client, char *var, char *val)
Definition: svmdb.c:334
int mutex_owner_pid
Definition: svm.h:44
static void region_unlock(svm_region_t *rp)
Definition: svmdb.c:60
static void notify_value(svmdb_value_t *v, svmdb_action_t a)
Definition: svmdb.c:146
pthread_mutex_t mutex
Definition: svm.h:42
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".