blob: 03dfe7c33d3c85c8245aaf9ee02b5450cb981970 [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 Barach8a7fb0c2016-07-08 14:44:23 -0400109 /* Add a bogus client (pid=0) so the svm won't be deallocated */
110 oldheap = svm_push_pvt_heap (db_rp);
111 vec_add1 (client->db_rp->client_pids, 0);
112 svm_pop_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700113
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400114 oldheap = svm_push_data_heap (db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400116 vec_validate (hp, 0);
117 hp->version = SVMDB_SHM_VERSION;
118 hp->namespaces[SVMDB_NAMESPACE_STRING]
119 = hash_create_string (0, sizeof (uword));
120 hp->namespaces[SVMDB_NAMESPACE_VEC]
121 = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400123 db_rp->user_ctx = hp;
124 client->shm = hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700125
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400126 svm_pop_heap (oldheap);
127 region_unlock (client->db_rp);
128 client->pid = getpid ();
129
130 return (client);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131}
132
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400133void
134svmdb_unmap (svmdb_client_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700135{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400136 ASSERT (client);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700137
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400138 if (!svm_get_root_rp ())
139 return;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700140
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400141 svm_region_unmap ((void *) client->db_rp);
142 svm_region_exit ();
143 vec_free (client);
144}
145
146static void
147notify_value (svmdb_value_t * v, svmdb_action_t a)
148{
149 int i;
150 int rv;
151 union sigval sv;
152 u32 value;
153 u32 *dead_registrations = 0;
154
155 svmdb_notify_t *np;
156
157 for (i = 0; i < vec_len (v->notifications); i++)
158 {
159 np = vec_elt_at_index (v->notifications, i);
160 if (np->action == a)
161 {
162 value = (np->action << 28) | (np->opaque);
163 sv.sival_ptr = (void *) (uword) value;
164 do
165 {
166 rv = 0;
167 if (sigqueue (np->pid, np->signum, sv) == 0)
168 break;
169 rv = errno;
170 }
171 while (rv == EAGAIN);
172 if (rv == 0)
173 continue;
174 vec_add1 (dead_registrations, i);
175 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176 }
177
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400178 for (i = 0; i < vec_len (dead_registrations); i++)
179 {
180 np = vec_elt_at_index (v->notifications, dead_registrations[i]);
181 clib_warning ("dead reg pid %d sig %d action %d opaque %x",
182 np->pid, np->signum, np->action, np->opaque);
183 vec_delete (v->notifications, 1, dead_registrations[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400185 vec_free (dead_registrations);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186}
187
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400188int
189svmdb_local_add_del_notification (svmdb_client_t * client,
190 svmdb_notification_args_t * a)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400192 uword *h;
193 void *oldheap;
194 hash_pair_t *hp;
195 svmdb_shm_hdr_t *shm;
196 u8 *dummy_value = 0;
197 svmdb_value_t *value;
198 svmdb_notify_t *np;
199 int i;
200 int rv = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700201
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400202 ASSERT (a->elsize);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400204 region_lock (client->db_rp, 18);
205 shm = client->shm;
206 oldheap = svm_push_data_heap (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700207
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400208 h = shm->namespaces[a->nspace];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400210 hp = hash_get_pair_mem (h, a->var);
211 if (hp == 0)
212 {
213 local_set_variable_nolock (client, a->nspace, (u8 *) a->var,
214 dummy_value, a->elsize);
215 /* might have moved */
216 h = shm->namespaces[a->nspace];
217 hp = hash_get_pair_mem (h, a->var);
218 ASSERT (hp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700219 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400220
221 value = pool_elt_at_index (shm->values, hp->value[0]);
222
223 for (i = 0; i < vec_len (value->notifications); i++)
224 {
225 np = vec_elt_at_index (value->notifications, i);
226 if ((np->pid == client->pid)
227 && (np->signum == a->signum)
228 && (np->action == a->action) && (np->opaque == a->opaque))
229 {
230 if (a->add_del == 0 /* delete */ )
231 {
232 vec_delete (value->notifications, 1, i);
233 goto out;
234 }
235 else
236 { /* add */
237 clib_warning
238 ("%s: ignore dup reg pid %d signum %d action %d opaque %x",
239 a->var, client->pid, a->signum, a->action, a->opaque);
240 rv = -2;
241 goto out;
242 }
243 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700244 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400245 if (a->add_del == 0)
246 {
247 rv = -3;
248 goto out;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400250
251 vec_add2 (value->notifications, np, 1);
252 np->pid = client->pid;
253 np->signum = a->signum;
254 np->action = a->action;
255 np->opaque = a->opaque;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700256
257out:
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400258 svm_pop_heap (oldheap);
259 region_unlock (client->db_rp);
260 return rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700261}
262
263
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400264static void
265local_unset_variable_nolock (svmdb_client_t * client,
266 svmdb_namespace_t namespace, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400268 uword *h;
269 svmdb_value_t *oldvalue;
270 hash_pair_t *hp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700271
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400272 h = client->shm->namespaces[namespace];
273 hp = hash_get_pair_mem (h, var);
274 if (hp)
275 {
276 oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
277 if (vec_len (oldvalue->notifications))
278 notify_value (oldvalue, SVMDB_ACTION_UNSET);
279 /* zero length value means unset */
280 _vec_len (oldvalue->value) = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400282 client->shm->namespaces[namespace] = h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283}
284
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400285void
286svmdb_local_unset_string_variable (svmdb_client_t * client, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700287{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400288 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400290 region_lock (client->db_rp, 11);
291 oldheap = svm_push_data_heap (client->db_rp);
292 local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var);
293 svm_pop_heap (oldheap);
294 region_unlock (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295}
296
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400297static void
298local_set_variable_nolock (svmdb_client_t * client,
299 svmdb_namespace_t namespace,
300 u8 * var, u8 * val, u32 elsize)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700301{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400302 uword *h;
303 hash_pair_t *hp;
304 u8 *name;
305 svmdb_shm_hdr_t *shm;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700306
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400307 shm = client->shm;
308 h = shm->namespaces[namespace];
309 hp = hash_get_pair_mem (h, var);
310 if (hp)
311 {
312 svmdb_value_t *oldvalue;
313 oldvalue = pool_elt_at_index (client->shm->values, hp->value[0]);
314 vec_alloc (oldvalue->value, vec_len (val) * elsize);
315 clib_memcpy (oldvalue->value, val, vec_len (val) * elsize);
316 _vec_len (oldvalue->value) = vec_len (val);
317 notify_value (oldvalue, SVMDB_ACTION_SET);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700318 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400319 else
320 {
321 svmdb_value_t *newvalue;
322 pool_get (shm->values, newvalue);
323 memset (newvalue, 0, sizeof (*newvalue));
324 newvalue->elsize = elsize;
325 vec_alloc (newvalue->value, vec_len (val) * elsize);
326 clib_memcpy (newvalue->value, val, vec_len (val) * elsize);
327 _vec_len (newvalue->value) = vec_len (val);
328 name = format (0, "%s%c", var, 0);
329 hash_set_mem (h, name, newvalue - shm->values);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400331 shm->namespaces[namespace] = h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332}
333
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400334void
335svmdb_local_set_string_variable (svmdb_client_t * client,
336 char *var, char *val)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700337{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400338 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400340 region_lock (client->db_rp, 12);
341 oldheap = svm_push_data_heap (client->db_rp);
342
343 local_unset_variable_nolock (client, SVMDB_NAMESPACE_STRING, var);
344
345 local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING,
346 (u8 *) var, (u8 *) val, 1 /* elsize */ );
347 svm_pop_heap (oldheap);
348 region_unlock (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349}
350
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400351static u8 *
352local_get_variable_nolock (svmdb_client_t * client,
353 svmdb_namespace_t namespace, u8 * var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700354{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400355 uword *h;
356 uword *p;
357 svmdb_shm_hdr_t *shm;
358 svmdb_value_t *oldvalue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700359
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400360 shm = client->shm;
361 h = shm->namespaces[namespace];
362 p = hash_get_mem (h, var);
363 if (p)
364 {
365 oldvalue = pool_elt_at_index (shm->values, p[0]);
366 notify_value (oldvalue, SVMDB_ACTION_GET);
367 return (oldvalue->value);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400369 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370}
371
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400372void *
373svmdb_local_get_variable_reference (svmdb_client_t * client,
374 svmdb_namespace_t namespace, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700375{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400376 u8 *rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400378 region_lock (client->db_rp, 19);
379 rv = local_get_variable_nolock (client, namespace, (u8 *) var);
380 region_unlock (client->db_rp);
381 return (void *) rv;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700382}
383
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400384char *
385svmdb_local_get_string_variable (svmdb_client_t * client, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700386{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400387 u8 *rv = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400389 region_lock (client->db_rp, 13);
390 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_STRING, (u8 *) var);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400392 if (rv && vec_len (rv))
393 {
394 rv = format (0, "%s", rv);
395 vec_add1 (rv, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 }
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400397 region_unlock (client->db_rp);
398 return ((char *) rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700399}
400
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400401void
402svmdb_local_dump_strings (svmdb_client_t * client)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700403{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400404 uword *h;
405 u8 *key;
406 u32 value;
407 svmdb_shm_hdr_t *shm = client->shm;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700408
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400409 region_lock (client->db_rp, 14);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700410
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400411 h = client->shm->namespaces[SVMDB_NAMESPACE_STRING];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700412
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400413 /* *INDENT-OFF* */
414 hash_foreach_mem(key, value, h,
415 ({
416 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700417
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400418 fformat(stdout, "%s: %s\n", key,
419 vec_len(v->value) ? v->value : (u8 *)"(nil)");
420 }));
421 /* *INDENT-ON* */
422 region_unlock (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700423}
424
Dave Barach23a74122016-11-24 16:34:20 -0500425int
426svmdb_local_serialize_strings (svmdb_client_t * client, char *filename)
427{
428 uword *h;
429 u8 *key;
430 u32 value;
431 svmdb_shm_hdr_t *shm = client->shm;
432 serialize_main_t _sm, *sm = &_sm;
433 clib_error_t *error = 0;
434 u8 *sanitized_name = 0;
435 int fd = 0;
436
437 if (strstr (filename, "..") || index (filename, '/'))
438 {
439 error = clib_error_return (0, "Illegal characters in filename '%s'",
440 filename);
441 goto out;
442 }
443
444 sanitized_name = format (0, "/tmp/%s%c", filename, 0);
445
446 fd = creat ((char *) sanitized_name, 0644);
447
448 if (fd < 0)
449 {
450 error = clib_error_return_unix (0, "Create '%s'", sanitized_name);
451 goto out;
452 }
453
454 serialize_open_unix_file_descriptor (sm, fd);
455
456 region_lock (client->db_rp, 20);
457
458 h = client->shm->namespaces[SVMDB_NAMESPACE_STRING];
459
460 serialize_likely_small_unsigned_integer (sm, hash_elts (h));
461
462 /* *INDENT-OFF* */
463 hash_foreach_mem(key, value, h,
464 ({
465 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
466
467 /* Omit names with nil values */
468 if (vec_len(v->value))
469 {
470 serialize_cstring (sm, (char *)key);
471 serialize_cstring (sm, (char *)v->value);
472 }
473 }));
474 /* *INDENT-ON* */
475 region_unlock (client->db_rp);
476
477 serialize_close (sm);
478
479out:
480 if (fd > 0 && close (fd) < 0)
481 error = clib_error_return_unix (0, "close fd %d", fd);
482
483 if (error)
484 {
485 clib_error_report (error);
486 return -1;
487 }
488 return 0;
489}
490
491int
492svmdb_local_unserialize_strings (svmdb_client_t * client, char *filename)
493{
494 serialize_main_t _sm, *sm = &_sm;
495 void *oldheap;
496 clib_error_t *error = 0;
497 u8 *key, *value;
498 int fd = 0;
499 u32 nelts;
500 int i;
501
502 fd = open (filename, O_RDONLY);
503
504 if (fd < 0)
505 {
506 error = clib_error_return_unix (0, "Failed to open '%s'", filename);
507 goto out;
508 }
509
510 unserialize_open_unix_file_descriptor (sm, fd);
511
512 region_lock (client->db_rp, 21);
513 oldheap = svm_push_data_heap (client->db_rp);
514
515 nelts = unserialize_likely_small_unsigned_integer (sm);
516
517 for (i = 0; i < nelts; i++)
518 {
519 unserialize_cstring (sm, (char **) &key);
520 unserialize_cstring (sm, (char **) &value);
521 local_set_variable_nolock (client, SVMDB_NAMESPACE_STRING,
522 key, value, 1 /* elsize */ );
523 vec_free (key);
524 vec_free (value);
525 }
526 svm_pop_heap (oldheap);
527 region_unlock (client->db_rp);
528
529 serialize_close (sm);
530
531out:
532 if (fd > 0 && close (fd) < 0)
533 error = clib_error_return_unix (0, "close fd %d", fd);
534
535 if (error)
536 {
537 clib_error_report (error);
538 return -1;
539 }
540 return 0;
541}
542
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400543void
544svmdb_local_unset_vec_variable (svmdb_client_t * client, char *var)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545{
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400546 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400548 region_lock (client->db_rp, 15);
549 oldheap = svm_push_data_heap (client->db_rp);
550 local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var);
551 svm_pop_heap (oldheap);
552 region_unlock (client->db_rp);
553}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400555void
556svmdb_local_set_vec_variable (svmdb_client_t * client,
557 char *var, void *val_arg, u32 elsize)
558{
559 u8 *val = (u8 *) val_arg;
560 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700561
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400562 region_lock (client->db_rp, 16);
563 oldheap = svm_push_data_heap (client->db_rp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400565 local_unset_variable_nolock (client, SVMDB_NAMESPACE_VEC, var);
566 local_set_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var,
567 val, elsize);
568
569 svm_pop_heap (oldheap);
570 region_unlock (client->db_rp);
571}
572
573void *
574svmdb_local_get_vec_variable (svmdb_client_t * client, char *var, u32 elsize)
575{
576 u8 *rv = 0;
577 u8 *copy = 0;
578
579 region_lock (client->db_rp, 17);
580
581 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
582
583 if (rv && vec_len (rv))
584 {
585 /* Make a copy in process-local memory */
586 vec_alloc (copy, vec_len (rv) * elsize);
587 clib_memcpy (copy, rv, vec_len (rv) * elsize);
588 _vec_len (copy) = vec_len (rv);
589 region_unlock (client->db_rp);
590 return (copy);
591 }
592 region_unlock (client->db_rp);
593 return (0);
594}
595
596void
597svmdb_local_dump_vecs (svmdb_client_t * client)
598{
599 uword *h;
600 u8 *key;
601 u32 value;
602 svmdb_shm_hdr_t *shm;
603
604 region_lock (client->db_rp, 17);
605 shm = client->shm;
606
607 h = client->shm->namespaces[SVMDB_NAMESPACE_VEC];
608
609 /* *INDENT-OFF* */
610 hash_foreach_mem(key, value, h,
611 ({
612 svmdb_value_t *v = pool_elt_at_index (shm->values, value);
613 (void) fformat(stdout, "%s:\n %U (%.2f)\n", key,
614 format_hex_bytes, v->value,
615 vec_len(v->value)*v->elsize, ((f64 *)(v->value))[0]);
616 }));
617 /* *INDENT-ON* */
618
619 region_unlock (client->db_rp);
620}
621
622void *
623svmdb_local_find_or_add_vec_variable (svmdb_client_t * client,
624 char *var, u32 nbytes)
625{
626 void *oldheap;
627 u8 *rv = 0;
628
629 region_lock (client->db_rp, 18);
630 oldheap = svm_push_data_heap (client->db_rp);
631
632 rv = local_get_variable_nolock (client, SVMDB_NAMESPACE_VEC, (u8 *) var);
633
634 if (rv)
635 {
636 goto out;
637 }
638 else
639 {
640 uword *h;
641 u8 *name;
642 svmdb_shm_hdr_t *shm;
643 svmdb_value_t *newvalue;
644
645 shm = client->shm;
646 h = shm->namespaces[SVMDB_NAMESPACE_VEC];
647
648 pool_get (shm->values, newvalue);
649 memset (newvalue, 0, sizeof (*newvalue));
650 newvalue->elsize = 1;
651 vec_alloc (newvalue->value, nbytes);
652 _vec_len (newvalue->value) = nbytes;
653 name = format (0, "%s%c", var, 0);
654 hash_set_mem (h, name, newvalue - shm->values);
655 shm->namespaces[SVMDB_NAMESPACE_VEC] = h;
656 rv = newvalue->value;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657 }
658
659out:
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400660 svm_pop_heap (oldheap);
661 region_unlock (client->db_rp);
662 return (rv);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663}
Dave Barach8a7fb0c2016-07-08 14:44:23 -0400664
665/*
666 * fd.io coding-style-patch-verification: ON
667 *
668 * Local Variables:
669 * eval: (c-set-style "gnu")
670 * End:
671 */