FD.io VPP  v16.06
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 
50 {
51  pthread_mutex_lock(&rp->mutex);
52 #ifdef MUTEX_DEBUG
53  rp->mutex_owner_pid = getpid();
54  rp->mutex_owner_tag = tag;
55 #endif
56 }
57 
59 {
60 #ifdef MUTEX_DEBUG
61  rp->mutex_owner_pid = 0;
62  rp->mutex_owner_tag = 0;
63 #endif
64  pthread_mutex_unlock(&rp->mutex);
65 }
66 
67 static svmdb_client_t *svmdb_map_internal (char *root_path, uword size)
68 {
69  svmdb_client_t *client = 0;
71  svm_region_t *db_rp;
72  void *oldheap;
73  svmdb_shm_hdr_t *hp = 0;
74 
75  vec_validate (client, 0);
76  vec_validate (a, 0);
77 
78  svm_region_init_chroot(root_path);
79 
80  a->root_path = root_path;
81  a->name = "/db";
82  a->size = size ? size : SVMDB_DEFAULT_SIZE;
84 
85  db_rp = client->db_rp = svm_region_find_or_create (a);
86 
87  ASSERT(db_rp);
88 
89  vec_free (a);
90 
91  region_lock (client->db_rp, 10);
92  /* Has someone else set up the shared-memory variable table? */
93  if (db_rp->user_ctx) {
94  client->shm = (void *) db_rp->user_ctx;
95  client->pid = getpid();
96  region_unlock (client->db_rp);
97  ASSERT (client->shm->version == SVMDB_SHM_VERSION);
98  return (client);
99  }
100  /* Nope, it's our problem... */
101 
102  /* Add a bogus client (pid=0) so the svm won't be deallocated */
103  oldheap = svm_push_pvt_heap (db_rp);
104  vec_add1(client->db_rp->client_pids, 0);
105  svm_pop_heap (oldheap);
106 
107  oldheap = svm_push_data_heap (db_rp);
108 
109  vec_validate(hp, 0);
112  = hash_create_string(0, sizeof(uword));
114  = hash_create_string(0, sizeof(uword));
115 
116  db_rp->user_ctx = hp;
117  client->shm = hp;
118 
119  svm_pop_heap (oldheap);
120  region_unlock (client->db_rp);
121  client->pid = getpid();
122 
123  return (client);
124 }
126 {
127  return svmdb_map_internal (0, 0);
128 }
129 
131 {
132  return svmdb_map_internal (0, size);
133 }
134 
136 {
137  return svmdb_map_internal (root_path, 0);
138 }
139 
141 {
142  return svmdb_map_internal (root_path, size);
143 }
144 
146 {
147  ASSERT(client);
148 
149  if (! svm_get_root_rp())
150  return;
151 
152  svm_region_unmap ((void *) client->db_rp);
153  svm_region_exit ();
154  vec_free(client);
155 }
156 
158 {
159  int i;
160  int rv;
161  union sigval sv;
162  u32 value;
163  u32 *dead_registrations = 0;
164 
165  svmdb_notify_t *np;
166 
167  for (i = 0; i < vec_len (v->notifications); i++) {
168  np = vec_elt_at_index (v->notifications, i);
169  if (np->action == a) {
170  value = (np->action<<28) | (np->opaque);
171  sv.sival_ptr = (void *)(uword)value;
172  do {
173  rv = 0;
174  if (sigqueue (np->pid, np->signum, sv) == 0)
175  break;
176  rv = errno;
177  } while (rv == EAGAIN);
178  if (rv == 0)
179  continue;
180  vec_add1 (dead_registrations, i);
181  }
182  }
183 
184  for (i = 0; i < vec_len (dead_registrations); i++) {
185  np = vec_elt_at_index (v->notifications, dead_registrations[i]);
186  clib_warning ("dead reg pid %d sig %d action %d opaque %x",
187  np->pid, np->signum, np->action, np->opaque);
188  vec_delete (v->notifications, 1, dead_registrations[i]);
189  }
190  vec_free (dead_registrations);
191 }
192 
195 {
196  uword *h;
197  void *oldheap;
198  hash_pair_t *hp;
199  svmdb_shm_hdr_t * shm;
200  u8 *dummy_value = 0;
201  svmdb_value_t *value;
202  svmdb_notify_t *np;
203  int i;
204  int rv = 0;
205 
206  ASSERT (a->elsize);
207 
208  region_lock (client->db_rp, 18);
209  shm = client->shm;
210  oldheap = svm_push_data_heap (client->db_rp);
211 
212  h = shm->namespaces[a->nspace];
213 
214  hp = hash_get_pair_mem (h, a->var);
215  if (hp == 0) {
216  local_set_variable_nolock (client, a->nspace, (u8 *)a->var,
217  dummy_value, a->elsize);
218  /* might have moved */
219  h = shm->namespaces[a->nspace];
220  hp = hash_get_pair_mem (h, a->var);
221  ASSERT(hp);
222  }
223 
224  value = pool_elt_at_index (shm->values, hp->value[0]);
225 
226  for (i = 0; i < vec_len (value->notifications); i++) {
227  np = vec_elt_at_index (value->notifications, i);
228  if ((np->pid == client->pid)
229  && (np->signum == a->signum)
230  && (np->action == a->action)
231  && (np->opaque == a->opaque)) {
232  if (a->add_del == 0 /* delete */) {
233  vec_delete (value->notifications, 1, i);
234  goto out;
235  } else { /* add */
236  clib_warning (
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  rv = -3;
246  goto out;
247  }
248 
249  vec_add2 (value->notifications, np, 1);
250  np->pid = client->pid;
251  np->signum = a->signum;
252  np->action = a->action;
253  np->opaque = a->opaque;
254 
255 out:
256  svm_pop_heap(oldheap);
257  region_unlock (client->db_rp);
258  return rv;
259 }
260 
261 
263  svmdb_namespace_t namespace,
264  char * var)
265 {
266  uword *h;
267  svmdb_value_t *oldvalue;
268  hash_pair_t *hp;
269 
270  h = client->shm->namespaces[namespace];
271  hp = hash_get_pair_mem (h, var);
272  if (hp) {
273  oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
274  if (vec_len (oldvalue->notifications))
275  notify_value (oldvalue, SVMDB_ACTION_UNSET);
276  /* zero length value means unset */
277  _vec_len (oldvalue->value) = 0;
278  }
279  client->shm->namespaces[namespace] = h;
280 }
281 
283 {
284  void *oldheap;
285 
286  region_lock (client->db_rp, 11);
287  oldheap = svm_push_data_heap (client->db_rp);
289  svm_pop_heap(oldheap);
290  region_unlock (client->db_rp);
291 }
292 
294  svmdb_namespace_t namespace,
295  u8 * var, u8 * val, u32 elsize)
296 {
297  uword *h;
298  hash_pair_t *hp;
299  u8 *name;
300  svmdb_shm_hdr_t * shm;
301 
302  shm = client->shm;
303  h = shm->namespaces[namespace];
304  hp = hash_get_pair_mem (h, var);
305  if (hp) {
306  svmdb_value_t * oldvalue;
307  oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
308  vec_alloc (oldvalue->value, vec_len(val)*elsize);
309  clib_memcpy (oldvalue->value, val, vec_len(val)*elsize);
310  _vec_len (oldvalue->value) = vec_len(val);
311  notify_value (oldvalue, SVMDB_ACTION_SET);
312  } else {
313  svmdb_value_t * newvalue;
314  pool_get (shm->values, newvalue);
315  memset (newvalue, 0, sizeof (*newvalue));
316  newvalue->elsize = elsize;
317  vec_alloc (newvalue->value, vec_len(val)*elsize);
318  clib_memcpy (newvalue->value, val, vec_len(val)*elsize);
319  _vec_len (newvalue->value) = vec_len(val);
320  name = format (0, "%s%c", var, 0);
321  hash_set_mem (h, name, newvalue - shm->values);
322  }
323  shm->namespaces[namespace] = h;
324 }
325 
327  char *var, char *val)
328 {
329  void *oldheap;
330 
331  region_lock (client->db_rp, 12);
332  oldheap = svm_push_data_heap (client->db_rp);
333 
335 
337  (u8 *) var, (u8 *) val, 1 /* elsize */);
338  svm_pop_heap(oldheap);
339  region_unlock (client->db_rp);
340 }
341 
343  svmdb_namespace_t namespace,
344  u8 * var)
345 {
346  uword *h;
347  uword *p;
348  svmdb_shm_hdr_t * shm;
349  svmdb_value_t *oldvalue;
350 
351  shm = client->shm;
352  h = shm->namespaces[namespace];
353  p = hash_get_mem (h, var);
354  if (p) {
355  oldvalue = pool_elt_at_index (shm->values, p[0]);
356  notify_value (oldvalue, SVMDB_ACTION_GET);
357  return (oldvalue->value);
358  }
359  return 0;
360 }
361 
363  svmdb_namespace_t namespace,
364  char *var)
365 {
366  u8 *rv;
367 
368  region_lock (client->db_rp, 19);
369  rv = local_get_variable_nolock (client, namespace, (u8 *)var);
370  region_unlock (client->db_rp);
371  return (void *)rv;
372 }
373 
375 {
376  u8 *rv = 0;
377 
378  region_lock (client->db_rp, 13);
379  rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_STRING, (u8 *) var);
380 
381  if (rv && vec_len (rv)) {
382  rv = format (0, "%s", rv);
383  vec_add1(rv, 0);
384  }
385  region_unlock (client->db_rp);
386  return ((char *) rv);
387 }
388 
390 {
391  uword *h;
392  u8 *key;
393  u32 value;
394  svmdb_shm_hdr_t *shm = client->shm;
395 
396  region_lock (client->db_rp, 14);
397 
398  h = client->shm->namespaces [SVMDB_NAMESPACE_STRING];
399 
400  hash_foreach_mem(key, value, h,
401  ({
402  svmdb_value_t *v = pool_elt_at_index (shm->values, value);
403 
404  fformat(stdout, "%s: %s\n", key,
405  vec_len(v->value) ? v->value : (u8 *)"(nil)");
406  }));
407  region_unlock (client->db_rp);
408 }
409 
411 {
412  void *oldheap;
413 
414  region_lock (client->db_rp, 15);
415  oldheap = svm_push_data_heap (client->db_rp);
417  svm_pop_heap(oldheap);
418  region_unlock (client->db_rp);
419 }
420 
422  char *var, void *val_arg, u32 elsize)
423 {
424  u8 *val = (u8 *)val_arg;
425  void *oldheap;
426 
427  region_lock (client->db_rp, 16);
428  oldheap = svm_push_data_heap (client->db_rp);
429 
432  val, elsize);
433 
434  svm_pop_heap(oldheap);
435  region_unlock (client->db_rp);
436 }
437 
438 void *svmdb_local_get_vec_variable (svmdb_client_t *client, char *var,
439  u32 elsize)
440 {
441  u8 *rv = 0;
442  u8 *copy = 0;
443 
444  region_lock (client->db_rp, 17);
445 
446  rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
447 
448  if (rv && vec_len(rv)) {
449  /* Make a copy in process-local memory */
450  vec_alloc (copy, vec_len(rv)*elsize);
451  clib_memcpy (copy, rv, vec_len(rv)*elsize);
452  _vec_len(copy) = vec_len(rv);
453  region_unlock (client->db_rp);
454  return (copy);
455  }
456  region_unlock (client->db_rp);
457  return (0);
458 }
459 
461 {
462  uword *h;
463  u8 *key;
464  u32 value;
465  svmdb_shm_hdr_t *shm;
466 
467  region_lock (client->db_rp, 17);
468  shm = client->shm;
469 
470  h = client->shm->namespaces [SVMDB_NAMESPACE_VEC];
471 
472  hash_foreach_mem(key, value, h,
473  ({
474  svmdb_value_t *v = pool_elt_at_index (shm->values, value);
475  (void) fformat(stdout, "%s:\n %U (%.2f)\n", key,
476  format_hex_bytes, v->value,
477  vec_len(v->value)*v->elsize, ((f64 *)(v->value))[0]);
478  }));
479 
480  region_unlock (client->db_rp);
481 }
482 
484  char *var, u32 nbytes)
485 {
486  void *oldheap;
487  u8 *rv = 0;
488 
489  region_lock (client->db_rp, 18);
490  oldheap = svm_push_data_heap (client->db_rp);
491 
492  rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *)var);
493 
494  if (rv) {
495  goto out;
496  } else {
497  uword *h;
498  u8 *name;
499  svmdb_shm_hdr_t * shm;
500  svmdb_value_t * newvalue;
501 
502  shm = client->shm;
504 
505  pool_get (shm->values, newvalue);
506  memset (newvalue, 0, sizeof (*newvalue));
507  newvalue->elsize = 1;
508  vec_alloc (newvalue->value, nbytes);
509  _vec_len (newvalue->value) = nbytes;
510  name = format (0, "%s%c", var, 0);
511  hash_set_mem (h, name, newvalue - shm->values);
513  rv = newvalue->value;
514  }
515 
516 out:
517  svm_pop_heap(oldheap);
518  region_unlock (client->db_rp);
519  return (rv);
520 }
char * root_path
Definition: svm.h:70
static svmdb_client_t * svmdb_map_internal(char *root_path, uword size)
Definition: svmdb.c:67
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
svm_region_t * svm_get_root_rp(void)
Definition: svm.c:53
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
static void svm_pop_heap(void *oldheap)
Definition: svm.h:179
void * svmdb_local_get_variable_reference(svmdb_client_t *client, svmdb_namespace_t namespace, char *var)
Definition: svmdb.c:362
a
Definition: bitmap.h:393
static void(BVT(clib_bihash)*h, BVT(clib_bihash_value)*v)
#define SVMDB_SHM_VERSION
Definition: svmdb.h:58
void svmdb_local_dump_vecs(svmdb_client_t *client)
Definition: svmdb.c:460
svmdb_namespace_t nspace
Definition: svmdb.h:69
void svmdb_local_unset_vec_variable(svmdb_client_t *client, char *var)
Definition: svmdb.c:410
svmdb_client_t * svmdb_map_chroot_size(char *root_path, uword size)
Definition: svmdb.c:140
svmdb_client_t * svmdb_map(void)
Definition: svmdb.c:125
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
int signum
Definition: svmdb.h:34
#define hash_set_mem(h, key, value)
Definition: hash.h:257
#define hash_get_pair_mem(h, key)
Definition: hash.h:254
u32 action
Definition: svmdb.h:35
#define pool_get(P, E)
Definition: pool.h:186
#define vec_alloc(V, N)
Allocate space for N more elements (no header, unspecified alignment)
Definition: vec.h:237
uword version
Definition: svmdb.h:52
void svmdb_unmap(svmdb_client_t *client)
Definition: svmdb.c:145
#define SVM_FLAGS_MHEAP
Definition: svm.h:32
uword value[0]
Definition: hash.h:151
svmdb_namespace_t
Definition: svmdb.h:45
void svmdb_local_dump_strings(svmdb_client_t *client)
Definition: svmdb.c:389
static void * svm_push_data_heap(svm_region_t *rp)
Definition: svm.h:172
#define always_inline
Definition: clib.h:84
uword * client_pids
Definition: svm.h:58
uword * namespaces[SVMDB_N_NAMESPACES]
Definition: svmdb.h:55
void * svm_region_find_or_create(svm_map_region_args_t *a)
Definition: svm.c:692
volatile void * user_ctx
Definition: svm.h:51
char * name
Definition: svm.h:71
#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:79
#define clib_warning(format, args...)
Definition: error.h:59
#define hash_create_string(elts, value_bytes)
Definition: hash.h:609
svmdb_shm_hdr_t * shm
Definition: svmdb.h:64
svmdb_action_t
Definition: svmdb.h:25
#define pool_elt_at_index(p, i)
Definition: pool.h:346
#define SVMDB_DEFAULT_SIZE
Definition: svmdb.h:81
char * svmdb_local_get_string_variable(svmdb_client_t *client, char *var)
Definition: svmdb.c:374
u32 elsize
Definition: svmdb.h:42
void svm_region_exit()
Definition: svm.c:918
#define hash_foreach_mem(key_var, value_var, h, body)
Definition: hash.h:399
static void * svm_push_pvt_heap(svm_region_t *rp)
Definition: svm.h:165
svm_region_t * db_rp
Definition: svmdb.h:63
static void local_unset_variable_nolock(svmdb_client_t *client, svmdb_namespace_t namespace, char *var)
Definition: svmdb.c:262
static u8 * local_get_variable_nolock(svmdb_client_t *client, svmdb_namespace_t namespace, u8 *var)
Definition: svmdb.c:342
void * svmdb_local_find_or_add_vec_variable(svmdb_client_t *client, char *var, u32 nbytes)
Definition: svmdb.c:483
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
#define clib_memcpy(a, b, c)
Definition: string.h:63
void svmdb_local_set_vec_variable(svmdb_client_t *client, char *var, void *val_arg, u32 elsize)
Definition: svmdb.c:421
svmdb_notify_t * notifications
Definition: svmdb.h:41
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
void svm_region_init_chroot(char *root_path)
Definition: svm.c:682
#define vec_delete(V, N, M)
Delete N elements starting at element M.
Definition: vec.h:743
always_inline void region_lock(svm_region_t *rp, int tag)
Definition: svmdb.c:49
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
u32 size
Definition: vhost-user.h:74
u32 opaque
Definition: svmdb.h:36
int svmdb_local_add_del_notification(svmdb_client_t *client, svmdb_notification_args_t *a)
Definition: svmdb.c:193
int mutex_owner_tag
Definition: svm.h:44
svmdb_client_t * svmdb_map_size(uword size)
Definition: svmdb.c:130
u64 uword
Definition: types.h:112
svmdb_client_t * svmdb_map_chroot(char *root_path)
Definition: svmdb.c:135
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:140
unsigned char u8
Definition: types.h:56
void svmdb_local_unset_string_variable(svmdb_client_t *client, char *var)
Definition: svmdb.c:282
static void local_set_variable_nolock(svmdb_client_t *client, svmdb_namespace_t namespace, u8 *var, u8 *val, u32 elsize)
Definition: svmdb.c:293
void svm_region_unmap(void *rp_arg)
Definition: svm.c:802
word fformat(FILE *f, char *fmt,...)
Definition: format.c:437
void * svmdb_local_get_vec_variable(svmdb_client_t *client, char *var, u32 elsize)
Definition: svmdb.c:438
#define hash_get_mem(h, key)
Definition: hash.h:251
u8 * value
Definition: svmdb.h:40
svmdb_value_t * values
Definition: svmdb.h:54
void svmdb_local_set_string_variable(svmdb_client_t *client, char *var, char *val)
Definition: svmdb.c:326
always_inline void region_unlock(svm_region_t *rp)
Definition: svmdb.c:58
int mutex_owner_pid
Definition: svm.h:43
static void notify_value(svmdb_value_t *v, svmdb_action_t a)
Definition: svmdb.c:157
pthread_mutex_t mutex
Definition: svm.h:41
CLIB vectors are ubiquitous dynamically resized arrays with by user defined "headers".