blob: 043b0924d8489f0b00c58574eef598c0d8ac8d09 [file] [log] [blame]
Dave Barach8a7fb0c2016-07-08 14:44:23 -04001/*
Ed Warnickecb9cada2015-12-08 15:45:58 -07002 *------------------------------------------------------------------
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>
Dave Barach23a74122016-11-24 16:34:20 -050042#include <vppinfra/serialize.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070043
44#include "svmdb.h"
45
Dave Barach8a7fb0c2016-07-08 14:44:23 -040046static void local_set_variable_nolock (svmdb_client_t * client,
47 svmdb_namespace_t namespace,
48 u8 * var, u8 * val, u32 elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -070049
Dave Barach8a7fb0c2016-07-08 14:44:23 -040050always_inline void
51region_lock (svm_region_t * rp, int tag)
Ed Warnickecb9cada2015-12-08 15:45:58 -070052{
Dave Barach8a7fb0c2016-07-08 14:44:23 -040053 pthread_mutex_lock (&rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -070054#ifdef MUTEX_DEBUG
Dave Barach8a7fb0c2016-07-08 14:44:23 -040055 rp->mutex_owner_pid = getpid ();
56 rp->mutex_owner_tag = tag;
57#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -070058}
59
Dave Barach8a7fb0c2016-07-08 14:44:23 -040060always_inline void
61region_unlock (svm_region_t * rp)
Ed Warnickecb9cada2015-12-08 15:45:58 -070062{
63#ifdef MUTEX_DEBUG
Dave Barach8a7fb0c2016-07-08 14:44:23 -040064 rp->mutex_owner_pid = 0;
65 rp->mutex_owner_tag = 0;
66#endif
67 pthread_mutex_unlock (&rp->mutex);
Ed Warnickecb9cada2015-12-08 15:45:58 -070068}
69
Dave Barach98cfc1a2016-07-18 14:23:36 -040070svmdb_client_t *
71svmdb_map (svmdb_map_args_t * dba)
Ed Warnickecb9cada2015-12-08 15:45:58 -070072{
Dave Barach8a7fb0c2016-07-08 14:44:23 -040073 svmdb_client_t *client = 0;
74 svm_map_region_args_t *a = 0;
75 svm_region_t *db_rp;
76 void *oldheap;
77 svmdb_shm_hdr_t *hp = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
Dave Barach8a7fb0c2016-07-08 14:44:23 -040079 vec_validate (client, 0);
80 vec_validate (a, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -070081
Dave Barach98cfc1a2016-07-18 14:23:36 -040082 svm_region_init_chroot_uid_gid (dba->root_path, dba->uid, dba->gid);
Ed Warnickecb9cada2015-12-08 15:45:58 -070083
Dave Barach98cfc1a2016-07-18 14:23:36 -040084 a->root_path = dba->root_path;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040085 a->name = "/db";
Dave Barach98cfc1a2016-07-18 14:23:36 -040086 a->size = dba->size ? dba->size : SVMDB_DEFAULT_SIZE;
Dave Barach8a7fb0c2016-07-08 14:44:23 -040087 a->flags = SVM_FLAGS_MHEAP;
Dave Barach98cfc1a2016-07-18 14:23:36 -040088 a->uid = dba->uid;
89 a->gid = dba->gid;
Ed Warnickecb9cada2015-12-08 15:45:58 -070090
Dave Barach8a7fb0c2016-07-08 14:44:23 -040091 db_rp = client->db_rp = svm_region_find_or_create (a);
Ed Warnickecb9cada2015-12-08 15:45:58 -070092
Dave Barach8a7fb0c2016-07-08 14:44:23 -040093 ASSERT (db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -070094
Dave Barach8a7fb0c2016-07-08 14:44:23 -040095 vec_free (a);
96
97 region_lock (client->db_rp, 10);
98 /* Has someone else set up the shared-memory variable table? */
99 if (db_rp->user_ctx)
100 {
101 client->shm = (void *) db_rp->user_ctx;
102 client->pid = getpid ();
103 region_unlock (client->db_rp);
104 ASSERT (client->shm->version == SVMDB_SHM_VERSION);
105 return (client);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400107 /* Nope, it's our problem... */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700108
Dave Wallaced756b352017-07-03 13:11:38 -0400109 if (CLIB_DEBUG > 2)
110 {
111 /* Add a bogus client (pid=0) so the svm won't be deallocated */
112 clib_warning
113 ("[%d] adding fake client (pid=0) so '%s' won't be unlinked",
114 getpid (), db_rp->region_name);
115 oldheap = svm_push_pvt_heap (db_rp);
116 vec_add1 (client->db_rp->client_pids, 0);
117 svm_pop_heap (oldheap);
118 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400119 oldheap = svm_push_data_heap (db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400121 vec_validate (hp, 0);
122 hp->version = SVMDB_SHM_VERSION;
123 hp->namespaces[SVMDB_NAMESPACE_STRING]
124 = hash_create_string (0, sizeof (uword));
125 hp->namespaces[SVMDB_NAMESPACE_VEC]
126 = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400128 db_rp->user_ctx = hp;
129 client->shm = hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400131 svm_pop_heap (oldheap);
132 region_unlock (client->db_rp);
133 client->pid = getpid ();
134
135 return (client);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136}
137
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400138void
139svmdb_unmap (svmdb_client_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400141 ASSERT (client);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400143 if (!svm_get_root_rp ())
144 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700145
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400146 svm_region_unmap ((void *) client->db_rp);
147 svm_region_exit ();
148 vec_free (client);
149}
150
151static void
152notify_value (svmdb_value_t * v, svmdb_action_t a)
153{
154 int i;
155 int rv;
156 union sigval sv;
157 u32 value;
158 u32 *dead_registrations = 0;
159
160 svmdb_notify_t *np;
161
162 for (i = 0; i < vec_len (v->notifications); i++)
163 {
164 np = vec_elt_at_index (v->notifications, i);
165 if (np->action == a)
166 {
167 value = (np->action << 28) | (np->opaque);
168 sv.sival_ptr = (void *) (uword) value;
169 do
170 {
171 rv = 0;
172 if (sigqueue (np->pid, np->signum, sv) == 0)
173 break;
174 rv = errno;
175 }
176 while (rv == EAGAIN);
177 if (rv == 0)
178 continue;
179 vec_add1 (dead_registrations, i);
180 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181 }
182
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400183 for (i = 0; i < vec_len (dead_registrations); i++)
184 {
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]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400190 vec_free (dead_registrations);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191}
192
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400193int
194svmdb_local_add_del_notification (svmdb_client_t * client,
195 svmdb_notification_args_t * a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400197 uword *h;
198 void *oldheap;
199 hash_pair_t *hp;
200 svmdb_shm_hdr_t *shm;
201 u8 *dummy_value = 0;
202 svmdb_value_t *value;
203 svmdb_notify_t *np;
204 int i;
205 int rv = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400207 ASSERT (a->elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400209 region_lock (client->db_rp, 18);
210 shm = client->shm;
211 oldheap = svm_push_data_heap (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400213 h = shm->namespaces[a->nspace];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700214
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400215 hp = hash_get_pair_mem (h, a->var);
216 if (hp == 0)
217 {
218 local_set_variable_nolock (client, a->nspace, (u8 *) a->var,
219 dummy_value, a->elsize);
220 /* might have moved */
221 h = shm->namespaces[a->nspace];
222 hp = hash_get_pair_mem (h, a->var);
223 ASSERT (hp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400225
226 value = pool_elt_at_index (shm->values, hp->value[0]);
227
228 for (i = 0; i < vec_len (value->notifications); i++)
229 {
230 np = vec_elt_at_index (value->notifications, i);
231 if ((np->pid == client->pid)
232 && (np->signum == a->signum)
233 && (np->action == a->action) && (np->opaque == a->opaque))
234 {
235 if (a->add_del == 0 /* delete */ )
236 {
237 vec_delete (value->notifications, 1, i);
238 goto out;
239 }
240 else
241 { /* add */
242 clib_warning
243 ("%s: ignore dup reg pid %d signum %d action %d opaque %x",
244 a->var, client->pid, a->signum, a->action, a->opaque);
245 rv = -2;
246 goto out;
247 }
248 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400250 if (a->add_del == 0)
251 {
252 rv = -3;
253 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400255
256 vec_add2 (value->notifications, np, 1);
257 np->pid = client->pid;
258 np->signum = a->signum;
259 np->action = a->action;
260 np->opaque = a->opaque;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261
262out:
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400263 svm_pop_heap (oldheap);
264 region_unlock (client->db_rp);
265 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266}
267
268
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400269static void
270local_unset_variable_nolock (svmdb_client_t * client,
271 svmdb_namespace_t namespace, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700272{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400273 uword *h;
274 svmdb_value_t *oldvalue;
275 hash_pair_t *hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700276
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400277 h = client->shm->namespaces[namespace];
278 hp = hash_get_pair_mem (h, var);
279 if (hp)
280 {
281 oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
282 if (vec_len (oldvalue->notifications))
283 notify_value (oldvalue, SVMDB_ACTION_UNSET);
284 /* zero length value means unset */
285 _vec_len (oldvalue->value) = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400287 client->shm->namespaces[namespace] = h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288}
289
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400290void
291svmdb_local_unset_string_variable (svmdb_client_t * client, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700292{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400293 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700294
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400295 region_lock (client->db_rp, 11);
296 oldheap = svm_push_data_heap (client->db_rp);
297 local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var);
298 svm_pop_heap (oldheap);
299 region_unlock (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700300}
301
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400302static void
303local_set_variable_nolock (svmdb_client_t * client,
304 svmdb_namespace_t namespace,
305 u8 * var, u8 * val, u32 elsize)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400307 uword *h;
308 hash_pair_t *hp;
309 u8 *name;
310 svmdb_shm_hdr_t *shm;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700311
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400312 shm = client->shm;
313 h = shm->namespaces[namespace];
314 hp = hash_get_pair_mem (h, var);
315 if (hp)
316 {
317 svmdb_value_t *oldvalue;
318 oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
319 vec_alloc (oldvalue->value, vec_len (val) * elsize);
320 clib_memcpy (oldvalue->value, val, vec_len (val) * elsize);
321 _vec_len (oldvalue->value) = vec_len (val);
322 notify_value (oldvalue, SVMDB_ACTION_SET);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700323 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400324 else
325 {
326 svmdb_value_t *newvalue;
327 pool_get (shm->values, newvalue);
328 memset (newvalue, 0, sizeof (*newvalue));
329 newvalue->elsize = elsize;
330 vec_alloc (newvalue->value, vec_len (val) * elsize);
331 clib_memcpy (newvalue->value, val, vec_len (val) * elsize);
332 _vec_len (newvalue->value) = vec_len (val);
333 name = format (0, "%s%c", var, 0);
334 hash_set_mem (h, name, newvalue - shm->values);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700335 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400336 shm->namespaces[namespace] = h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337}
338
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400339void
340svmdb_local_set_string_variable (svmdb_client_t * client,
341 char *var, char *val)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400343 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400345 region_lock (client->db_rp, 12);
346 oldheap = svm_push_data_heap (client->db_rp);
347
348 local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var);
349
350 local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING,
351 (u8 *) var, (u8 *) val, 1 /* elsize */ );
352 svm_pop_heap (oldheap);
353 region_unlock (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354}
355
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400356static u8 *
357local_get_variable_nolock (svmdb_client_t * client,
358 svmdb_namespace_t namespace, u8 * var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400360 uword *h;
361 uword *p;
362 svmdb_shm_hdr_t *shm;
363 svmdb_value_t *oldvalue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400365 shm = client->shm;
366 h = shm->namespaces[namespace];
367 p = hash_get_mem (h, var);
368 if (p)
369 {
370 oldvalue = pool_elt_at_index (shm->values, p[0]);
371 notify_value (oldvalue, SVMDB_ACTION_GET);
372 return (oldvalue->value);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700373 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400374 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700375}
376
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400377void *
378svmdb_local_get_variable_reference (svmdb_client_t * client,
379 svmdb_namespace_t namespace, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700380{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400381 u8 *rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400383 region_lock (client->db_rp, 19);
384 rv = local_get_variable_nolock (client, namespace, (u8 *) var);
385 region_unlock (client->db_rp);
386 return (void *) rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700387}
388
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400389char *
390svmdb_local_get_string_variable (svmdb_client_t * client, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400392 u8 *rv = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400394 region_lock (client->db_rp, 13);
395 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_STRING, (u8 *) var);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400397 if (rv && vec_len (rv))
398 {
399 rv = format (0, "%s", rv);
400 vec_add1 (rv, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400402 region_unlock (client->db_rp);
403 return ((char *) rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404}
405
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400406void
407svmdb_local_dump_strings (svmdb_client_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400409 uword *h;
410 u8 *key;
411 u32 value;
412 svmdb_shm_hdr_t *shm = client->shm;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400414 region_lock (client->db_rp, 14);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700415
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400416 h = client->shm->namespaces[SVMDB_NAMESPACE_STRING];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400418 /* *INDENT-OFF* */
419 hash_foreach_mem(key, value, h,
420 ({
421 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400423 fformat(stdout, "%s: %s\n", key,
424 vec_len(v->value) ? v->value : (u8 *)"(nil)");
425 }));
426 /* *INDENT-ON* */
427 region_unlock (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428}
429
Dave Barach23a74122016-11-24 16:34:20 -0500430int
431svmdb_local_serialize_strings (svmdb_client_t * client, char *filename)
432{
433 uword *h;
434 u8 *key;
435 u32 value;
436 svmdb_shm_hdr_t *shm = client->shm;
437 serialize_main_t _sm, *sm = &_sm;
438 clib_error_t *error = 0;
439 u8 *sanitized_name = 0;
440 int fd = 0;
441
442 if (strstr (filename, "..") || index (filename, '/'))
443 {
444 error = clib_error_return (0, "Illegal characters in filename '%s'",
445 filename);
446 goto out;
447 }
448
449 sanitized_name = format (0, "/tmp/%s%c", filename, 0);
450
451 fd = creat ((char *) sanitized_name, 0644);
452
453 if (fd < 0)
454 {
455 error = clib_error_return_unix (0, "Create '%s'", sanitized_name);
456 goto out;
457 }
458
459 serialize_open_unix_file_descriptor (sm, fd);
460
461 region_lock (client->db_rp, 20);
462
463 h = client->shm->namespaces[SVMDB_NAMESPACE_STRING];
464
465 serialize_likely_small_unsigned_integer (sm, hash_elts (h));
466
467 /* *INDENT-OFF* */
468 hash_foreach_mem(key, value, h,
469 ({
470 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
471
472 /* Omit names with nil values */
473 if (vec_len(v->value))
474 {
475 serialize_cstring (sm, (char *)key);
476 serialize_cstring (sm, (char *)v->value);
477 }
478 }));
479 /* *INDENT-ON* */
480 region_unlock (client->db_rp);
481
482 serialize_close (sm);
483
484out:
485 if (fd > 0 && close (fd) < 0)
486 error = clib_error_return_unix (0, "close fd %d", fd);
487
488 if (error)
489 {
490 clib_error_report (error);
491 return -1;
492 }
493 return 0;
494}
495
496int
497svmdb_local_unserialize_strings (svmdb_client_t * client, char *filename)
498{
499 serialize_main_t _sm, *sm = &_sm;
500 void *oldheap;
501 clib_error_t *error = 0;
502 u8 *key, *value;
503 int fd = 0;
504 u32 nelts;
505 int i;
506
507 fd = open (filename, O_RDONLY);
508
509 if (fd < 0)
510 {
511 error = clib_error_return_unix (0, "Failed to open '%s'", filename);
512 goto out;
513 }
514
515 unserialize_open_unix_file_descriptor (sm, fd);
516
517 region_lock (client->db_rp, 21);
518 oldheap = svm_push_data_heap (client->db_rp);
519
520 nelts = unserialize_likely_small_unsigned_integer (sm);
521
522 for (i = 0; i < nelts; i++)
523 {
524 unserialize_cstring (sm, (char **) &key);
525 unserialize_cstring (sm, (char **) &value);
526 local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING,
527 key, value, 1 /* elsize */ );
528 vec_free (key);
529 vec_free (value);
530 }
531 svm_pop_heap (oldheap);
532 region_unlock (client->db_rp);
533
534 serialize_close (sm);
535
536out:
537 if (fd > 0 && close (fd) < 0)
538 error = clib_error_return_unix (0, "close fd %d", fd);
539
540 if (error)
541 {
542 clib_error_report (error);
543 return -1;
544 }
545 return 0;
546}
547
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400548void
549svmdb_local_unset_vec_variable (svmdb_client_t * client, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700550{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400551 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700552
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400553 region_lock (client->db_rp, 15);
554 oldheap = svm_push_data_heap (client->db_rp);
555 local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var);
556 svm_pop_heap (oldheap);
557 region_unlock (client->db_rp);
558}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700559
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400560void
561svmdb_local_set_vec_variable (svmdb_client_t * client,
562 char *var, void *val_arg, u32 elsize)
563{
564 u8 *val = (u8 *) val_arg;
565 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700566
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400567 region_lock (client->db_rp, 16);
568 oldheap = svm_push_data_heap (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400570 local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var);
571 local_set_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var,
572 val, elsize);
573
574 svm_pop_heap (oldheap);
575 region_unlock (client->db_rp);
576}
577
578void *
579svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, u32 elsize)
580{
581 u8 *rv = 0;
582 u8 *copy = 0;
583
584 region_lock (client->db_rp, 17);
585
586 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
587
588 if (rv && vec_len (rv))
589 {
590 /* Make a copy in process-local memory */
591 vec_alloc (copy, vec_len (rv) * elsize);
592 clib_memcpy (copy, rv, vec_len (rv) * elsize);
593 _vec_len (copy) = vec_len (rv);
594 region_unlock (client->db_rp);
595 return (copy);
596 }
597 region_unlock (client->db_rp);
598 return (0);
599}
600
601void
602svmdb_local_dump_vecs (svmdb_client_t * client)
603{
604 uword *h;
605 u8 *key;
606 u32 value;
607 svmdb_shm_hdr_t *shm;
608
609 region_lock (client->db_rp, 17);
610 shm = client->shm;
611
612 h = client->shm->namespaces[SVMDB_NAMESPACE_VEC];
613
614 /* *INDENT-OFF* */
615 hash_foreach_mem(key, value, h,
616 ({
617 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
618 (void) fformat(stdout, "%s:\n %U (%.2f)\n", key,
619 format_hex_bytes, v->value,
620 vec_len(v->value)*v->elsize, ((f64 *)(v->value))[0]);
621 }));
622 /* *INDENT-ON* */
623
624 region_unlock (client->db_rp);
625}
626
627void *
628svmdb_local_find_or_add_vec_variable (svmdb_client_t * client,
629 char *var, u32 nbytes)
630{
631 void *oldheap;
632 u8 *rv = 0;
633
634 region_lock (client->db_rp, 18);
635 oldheap = svm_push_data_heap (client->db_rp);
636
637 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
638
639 if (rv)
640 {
641 goto out;
642 }
643 else
644 {
645 uword *h;
646 u8 *name;
647 svmdb_shm_hdr_t *shm;
648 svmdb_value_t *newvalue;
649
650 shm = client->shm;
651 h = shm->namespaces[SVMDB_NAMESPACE_VEC];
652
653 pool_get (shm->values, newvalue);
654 memset (newvalue, 0, sizeof (*newvalue));
655 newvalue->elsize = 1;
656 vec_alloc (newvalue->value, nbytes);
657 _vec_len (newvalue->value) = nbytes;
658 name = format (0, "%s%c", var, 0);
659 hash_set_mem (h, name, newvalue - shm->values);
660 shm->namespaces[SVMDB_NAMESPACE_VEC] = h;
661 rv = newvalue->value;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700662 }
663
664out:
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400665 svm_pop_heap (oldheap);
666 region_unlock (client->db_rp);
667 return (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700668}
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400669
670/*
671 * fd.io coding-style-patch-verification: ON
672 *
673 * Local Variables:
674 * eval: (c-set-style "gnu")
675 * End:
676 */