FD.io VPP  v16.06
Vector Packet Processing
ssvm_eth.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "ssvm_eth.h"
16 
18 
19 #define foreach_ssvm_eth_tx_func_error \
20 _(RING_FULL, "Tx packet drops (ring full)") \
21 _(NO_BUFFERS, "Tx packet drops (no buffers)") \
22 _(ADMIN_DOWN, "Tx packet drops (admin down)")
23 
24 typedef enum {
25 #define _(f,s) SSVM_ETH_TX_ERROR_##f,
27 #undef _
30 
31 static u32 ssvm_eth_flag_change (vnet_main_t * vnm,
33  u32 flags);
34 
35 int ssvm_eth_create (ssvm_eth_main_t * em, u8 * name, int is_master)
36 {
37  ssvm_private_t * intfc;
38  void * oldheap;
39  clib_error_t * e;
42  ssvm_eth_queue_elt_t * elts;
43  u32 * elt_indices;
44  u8 enet_addr[6];
45  int i, rv;
46 
47  vec_add2 (em->intfcs, intfc, 1);
48 
49  intfc->ssvm_size = em->segment_size;
50  intfc->i_am_master = 1;
51  intfc->name = name;
52  intfc->my_pid = getpid();
53  if (is_master == 0)
54  {
55  rv = ssvm_slave_init (intfc, 20 /* timeout in seconds */);
56  if (rv < 0)
57  return rv;
58  goto create_vnet_interface;
59  }
60 
61  intfc->requested_va = em->next_base_va;
62  em->next_base_va += em->segment_size;
63  rv = ssvm_master_init (intfc, intfc - em->intfcs /* master index */);
64 
65  if (rv < 0)
66  return rv;
67 
68  /* OK, segment created, set up queues and so forth. */
69 
70  sh = intfc->sh;
71  oldheap = ssvm_push_heap (sh);
72 
73  q = unix_shared_memory_queue_init (em->queue_elts, sizeof (u32),
74  0 /* consumer pid not interesting */,
75  0 /* signal not sent */);
76  sh->opaque [TO_MASTER_Q_INDEX] = (void *)q;
77  q = unix_shared_memory_queue_init (em->queue_elts, sizeof (u32),
78  0 /* consumer pid not interesting */,
79  0 /* signal not sent */);
80  sh->opaque [TO_SLAVE_Q_INDEX] = (void *)q;
81 
82  /*
83  * Preallocate the requested number of buffer chunks
84  * There must be a better way to do this, etc.
85  * Add some slop to avoid pool reallocation, which will not go well
86  */
87  elts = 0;
88  elt_indices = 0;
89 
91  vec_validate_aligned (elt_indices, em->nbuffers - 1, CLIB_CACHE_LINE_BYTES);
92 
93  for (i = 0; i < em->nbuffers; i++)
94  elt_indices[i] = i;
95 
96  sh->opaque [CHUNK_POOL_INDEX] = (void *) elts;
97  sh->opaque [CHUNK_POOL_FREELIST_INDEX] = (void *) elt_indices;
98  sh->opaque [CHUNK_POOL_NFREE] = (void *)(uword) em->nbuffers;
99 
100  ssvm_pop_heap (oldheap);
101 
102  create_vnet_interface:
103 
104  sh = intfc->sh;
105 
106  memset (enet_addr, 0, sizeof (enet_addr));
107  enet_addr[0] = 2;
108  enet_addr[1] = 0xFE;
109  enet_addr[2] = is_master;
110  enet_addr[5] = sh->master_index;
111 
113  (em->vnet_main, ssvm_eth_device_class.index,
114  intfc - em->intfcs,
115  /* ethernet address */ enet_addr,
116  &intfc->vlib_hw_if_index,
118 
119  if (e)
120  {
121  clib_error_report (e);
122  /* $$$$ unmap offending region? */
123  return VNET_API_ERROR_INVALID_INTERFACE;
124  }
125 
126  /* Declare link up */
129 
130  /* Let the games begin... */
131  if (is_master)
132  sh->ready = 1;
133  return 0;
134 }
135 
136 static clib_error_t *
138 {
139  u8 * name;
140  int is_master = 1;
141  int i, rv;
143 
145  {
146  if (unformat (input, "base-va %llx", &em->next_base_va))
147  ;
148  else if (unformat (input, "segment-size %lld", &em->segment_size))
149  em->segment_size = 1ULL << (max_log2 (em->segment_size));
150  else if (unformat (input, "nbuffers %lld", &em->nbuffers))
151  ;
152  else if (unformat (input, "queue-elts %lld", &em->queue_elts))
153  ;
154  else if (unformat (input, "slave"))
155  is_master = 0;
156  else if (unformat (input, "%s", &name))
157  vec_add1 (em->names, name);
158  else
159  break;
160  }
161 
162  /* No configured instances, we're done... */
163  if (vec_len (em->names) == 0)
164  return 0;
165 
166  for (i = 0; i < vec_len (em->names); i++)
167  {
168  rv = ssvm_eth_create (em, em->names[i], is_master);
169  if (rv < 0)
170  return clib_error_return (0, "ssvm_eth_create '%s' failed, error %d",
171  em->names[i], rv);
172  }
173 
174  vlib_node_set_state (vm, ssvm_eth_input_node.index, VLIB_NODE_STATE_POLLING);
175 
176  return 0;
177 }
178 
179 VLIB_CONFIG_FUNCTION (ssvm_config, "ssvm_eth");
180 
181 
183 {
185 
188  clib_warning ("ssvm_eth_queue_elt_t size %d not a multiple of %d",
189  sizeof(ssvm_eth_queue_elt_t), CLIB_CACHE_LINE_BYTES);
190 
191  em->vlib_main = vm;
192  em->vnet_main = vnet_get_main();
193  em->elog_main = &vm->elog_main;
194 
195  /* default config param values... */
196 
197  em->next_base_va = 0x600000000ULL;
198  /*
199  * Allocate 2 full superframes in each dir (256 x 2 x 2 x 2048 bytes),
200  * 2mb; double that so we have plenty of space... 4mb
201  */
202  em->segment_size = 8<<20;
203  em->nbuffers = 1024;
204  em->queue_elts = 512;
205  return 0;
206 }
207 
209 
211 #define _(n,s) s,
213 #undef _
214 };
215 
216 static u8 * format_ssvm_eth_device_name (u8 * s, va_list * args)
217 {
218  u32 i = va_arg (*args, u32);
219 
220  s = format (s, "ssvmEthernet%d", i);
221  return s;
222 }
223 
224 static u8 * format_ssvm_eth_device (u8 * s, va_list * args)
225 {
226  s = format (s, "SSVM Ethernet");
227  return s;
228 }
229 
230 static u8 * format_ssvm_eth_tx_trace (u8 * s, va_list * args)
231 {
232  s = format (s, "Unimplemented...");
233  return s;
234 }
235 
236 
237 static uword
239  vlib_node_runtime_t * node,
240  vlib_frame_t * f)
241 {
243  vnet_interface_output_runtime_t * rd = (void *) node->runtime_data;
244  ssvm_private_t * intfc = vec_elt_at_index (em->intfcs, rd->dev_instance);
245  ssvm_shared_header_t * sh = intfc->sh;
247  u32 * from;
248  u32 n_left;
249  ssvm_eth_queue_elt_t * elts, * elt, * prev_elt;
250  u32 my_pid = intfc->my_pid;
251  vlib_buffer_t * b0;
252  u32 bi0;
253  u32 size_this_buffer;
254  u32 chunks_this_buffer;
255  u8 i_am_master = intfc->i_am_master;
256  u32 elt_index;
257  int is_ring_full, interface_down;
258  int i;
259  volatile u32 *queue_lock;
260  u32 n_to_alloc = VLIB_FRAME_SIZE;
261  u32 n_allocated, n_present_in_cache, n_available;
262  u32 * elt_indices;
263 
264  if (i_am_master)
266  else
268 
269  queue_lock = (u32 *) q;
270 
271  from = vlib_frame_vector_args (f);
272  n_left = f->n_vectors;
273  is_ring_full = 0;
274  interface_down = 0;
275 
276  n_present_in_cache = vec_len (em->chunk_cache);
277 
278  /* admin / link up/down check */
279  if (sh->opaque [MASTER_ADMIN_STATE_INDEX] == 0 ||
280  sh->opaque [SLAVE_ADMIN_STATE_INDEX] == 0)
281  {
282  interface_down = 1;
283  goto out;
284  }
285 
286  ssvm_lock (sh, my_pid, 1);
287 
288  elts = (ssvm_eth_queue_elt_t *) (sh->opaque [CHUNK_POOL_INDEX]);
289  elt_indices = (u32 *) (sh->opaque [CHUNK_POOL_FREELIST_INDEX]);
290  n_available = (u32) pointer_to_uword(sh->opaque [CHUNK_POOL_NFREE]);
291 
292  if (n_present_in_cache < n_left*2)
293  {
295  n_to_alloc + n_present_in_cache - 1);
296 
297  n_allocated = n_to_alloc < n_available ? n_to_alloc : n_available;
298 
299  if (PREDICT_TRUE(n_allocated > 0))
300  {
301  clib_memcpy (&em->chunk_cache[n_present_in_cache],
302  &elt_indices[n_available - n_allocated],
303  sizeof(u32) * n_allocated);
304  }
305 
306  n_present_in_cache += n_allocated;
307  n_available -= n_allocated;
308  sh->opaque [CHUNK_POOL_NFREE] = uword_to_pointer(n_available, void*);
309  _vec_len (em->chunk_cache) = n_present_in_cache;
310  }
311 
312  ssvm_unlock (sh);
313 
314  while (n_left)
315  {
316  bi0 = from[0];
317  b0 = vlib_get_buffer (vm, bi0);
318 
319  size_this_buffer = vlib_buffer_length_in_chain (vm, b0);
320  chunks_this_buffer = (size_this_buffer + (SSVM_BUFFER_SIZE - 1))
322 
323  /* If we're not going to be able to enqueue the buffer, tail drop. */
324  if (q->cursize >= q->maxsize)
325  {
326  is_ring_full = 1;
327  break;
328  }
329 
330  prev_elt = 0;
331  elt_index = ~0;
332  for (i = 0; i < chunks_this_buffer; i++)
333  {
334  if (PREDICT_FALSE (n_present_in_cache == 0))
335  goto out;
336 
337  elt_index = em->chunk_cache[--n_present_in_cache];
338  elt = elts + elt_index;
339 
340  elt->type = SSVM_PACKET_TYPE;
341  elt->flags = 0;
345  elt->current_data_hint = b0->current_data;
346  elt->owner = !i_am_master;
347  elt->tag = 1;
348 
349  clib_memcpy (elt->data, b0->data + b0->current_data, b0->current_length);
350 
351  if (PREDICT_FALSE (prev_elt != 0))
352  prev_elt->next_index = elt - elts;
353 
354  if (PREDICT_FALSE(i < (chunks_this_buffer-1)))
355  {
358  b0 = vlib_get_buffer (vm, b0->next_buffer);
359  }
360  prev_elt = elt;
361  }
362 
363  while (__sync_lock_test_and_set (queue_lock, 1))
364  ;
365 
366  unix_shared_memory_queue_add_raw (q, (u8 *)&elt_index);
368  *queue_lock = 0;
369 
370  from++;
371  n_left--;
372  }
373 
374  out:
375  if (PREDICT_FALSE(n_left))
376  {
377  if (is_ring_full)
378  vlib_error_count (vm, node->node_index, SSVM_ETH_TX_ERROR_RING_FULL,
379  n_left);
380  else if (interface_down)
381  vlib_error_count (vm, node->node_index, SSVM_ETH_TX_ERROR_ADMIN_DOWN,
382  n_left);
383  else
384  vlib_error_count (vm, node->node_index, SSVM_ETH_TX_ERROR_NO_BUFFERS,
385  n_left);
386 
387  vlib_buffer_free (vm, from, n_left);
388  }
389  else
391 
392  if (PREDICT_TRUE(vec_len(em->chunk_cache)))
393  _vec_len(em->chunk_cache) = n_present_in_cache;
394 
395  return f->n_vectors;
396 }
397 
399 {
400  /* Nothing for now */
401 }
402 
403 static clib_error_t *
405 {
406  vnet_hw_interface_t * hif = vnet_get_hw_interface (vnm, hw_if_index);
407  uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
409  ssvm_private_t * intfc = vec_elt_at_index (em->intfcs, hif->dev_instance);
411 
412  /* publish link-state in shared-memory, to discourage buffer-wasting */
413  sh = intfc->sh;
414  if (intfc->i_am_master)
415  sh->opaque [MASTER_ADMIN_STATE_INDEX] = (void *) is_up;
416  else
417  sh->opaque [SLAVE_ADMIN_STATE_INDEX] = (void *) is_up;
418 
419  return 0;
420 }
421 
422 static clib_error_t *
424  u32 hw_if_index,
425  struct vnet_sw_interface_t * st,
426  int is_add)
427 {
428  /* Nothing for now */
429  return 0;
430 }
431 
432 /*
433  * Dynamically redirect all pkts from a specific interface
434  * to the specified node
435  */
436 static void
438  u32 node_index)
439 {
441  vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
443 
444  /* Shut off redirection */
445  if (node_index == ~0)
446  {
447  intfc->per_interface_next_index = node_index;
448  return;
449  }
450 
451  intfc->per_interface_next_index =
452  vlib_node_add_next (em->vlib_main, ssvm_eth_input_node.index, node_index);
453 }
454 
457  u32 flags)
458 {
459  /* nothing for now */
460  return 0;
461 }
462 
464  .name = "ssvm-eth",
465  .tx_function = ssvm_eth_interface_tx,
466  .tx_function_n_errors = SSVM_ETH_TX_N_ERROR,
467  .tx_function_error_strings = ssvm_eth_tx_func_error_strings,
468  .format_device_name = format_ssvm_eth_device_name,
469  .format_device = format_ssvm_eth_device,
470  .format_tx_trace = format_ssvm_eth_tx_trace,
471  .clear_counters = ssvm_eth_clear_hw_interface_counters,
472  .admin_up_down_function = ssvm_eth_interface_admin_up_down,
473  .subif_add_del_function = ssvm_eth_subif_add_del_function,
474  .rx_redirect_to_node = ssvm_eth_set_interface_next_node,
475  .no_flatten_output_chains = 1,
476 };
u64 segment_size
Definition: ssvm_eth.h:69
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
u64 ssvm_size
Definition: ssvm.h:72
vmrglw vmrglh hi
always_inline void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
Definition: error_funcs.h:54
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
elog_main_t * elog_main
Definition: ssvm_eth.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
uword requested_va
Definition: ssvm.h:76
u32 vlib_hw_if_index
Definition: ssvm.h:74
clib_error_t * vnet_hw_interface_set_flags(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: interface.c:454
int ssvm_master_init(ssvm_private_t *ssvm, u32 master_index)
Definition: ssvm.c:17
#define PREDICT_TRUE(x)
Definition: clib.h:98
volatile u32 ready
Definition: ssvm.h:64
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
void * opaque[SSVM_N_OPAQUE]
Definition: ssvm.h:61
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
#define SSVM_BUFFER_NEXT_PRESENT
Definition: ssvm_eth.h:45
#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
always_inline uword max_log2(uword x)
Definition: clib.h:216
static char * ssvm_eth_tx_func_error_strings[]
Definition: ssvm_eth.c:210
ssvm_shared_header_t * sh
Definition: ssvm.h:71
#define clib_error_report(e)
Definition: error.h:126
#define VNET_HW_INTERFACE_FLAG_LINK_UP
Definition: interface.h:241
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:405
always_inline void ssvm_unlock(ssvm_shared_header_t *h)
Definition: ssvm.h:98
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
static void ssvm_eth_set_interface_next_node(vnet_main_t *vnm, u32 hw_if_index, u32 node_index)
Definition: ssvm_eth.c:437
u32 * chunk_cache
Definition: ssvm_eth.h:64
static u8 * format_ssvm_eth_device_name(u8 *s, va_list *args)
Definition: ssvm_eth.c:216
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
i16 current_data
signed offset in data[], pre_data[] that we are currently processing.
Definition: buffer.h:77
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
always_inline void ssvm_lock(ssvm_shared_header_t *h, u32 my_pid, u32 tag)
Definition: ssvm.h:82
int ssvm_eth_create(ssvm_eth_main_t *em, u8 *name, int is_master)
Definition: ssvm_eth.c:35
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
always_inline void vlib_node_set_state(vlib_main_t *vm, u32 node_index, vlib_node_state_t new_state)
Definition: node_funcs.h:100
static void * ssvm_push_heap(ssvm_shared_header_t *sh)
Definition: ssvm.h:109
VNET_DEVICE_CLASS(ssvm_eth_device_class)
always_inline uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:112
#define clib_warning(format, args...)
Definition: error.h:59
vnet_device_class_t ssvm_eth_device_class
vlib_node_registration_t ssvm_eth_input_node
(constructor) VLIB_REGISTER_NODE (ssvm_eth_input_node)
Definition: node.c:17
static void ssvm_pop_heap(void *oldheap)
Definition: ssvm.h:116
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
static uword pointer_to_uword(const void *p)
Definition: types.h:131
#define VLIB_BUFFER_NEXT_PRESENT
Definition: buffer.h:93
vnet_main_t * vnet_main
Definition: ssvm_eth.h:78
static uword ssvm_eth_interface_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *f)
Definition: ssvm_eth.c:238
static u8 * format_ssvm_eth_tx_trace(u8 *s, va_list *args)
Definition: ssvm_eth.c:230
#define pool_elt_at_index(p, i)
Definition: pool.h:346
void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
Definition: buffer.c:1060
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
static void ssvm_eth_clear_hw_interface_counters(u32 instance)
Definition: ssvm_eth.c:398
vlib_main_t * vlib_main
Definition: ssvm_eth.h:77
u32 per_interface_next_index
Definition: ssvm.h:78
int ssvm_slave_init(ssvm_private_t *ssvm, int timeout_in_seconds)
Definition: ssvm.c:94
#define PREDICT_FALSE(x)
Definition: clib.h:97
#define VLIB_CONFIG_FUNCTION(x, n,...)
Definition: init.h:116
ssvm_private_t * intfcs
Definition: ssvm_eth.h:61
#define VLIB_FRAME_SIZE
Definition: node.h:292
static u8 * format_ssvm_eth_device(u8 *s, va_list *args)
Definition: ssvm_eth.c:224
#define uword_to_pointer(u, type)
Definition: types.h:134
u16 n_vectors
Definition: node.h:307
#define SSVM_BUFFER_SIZE
Definition: ssvm_eth.h:37
#define clib_memcpy(a, b, c)
Definition: string.h:63
elog_main_t elog_main
Definition: main.h:141
u32 my_pid
Definition: ssvm.h:73
static clib_error_t * ssvm_eth_subif_add_del_function(vnet_main_t *vnm, u32 hw_if_index, struct vnet_sw_interface_t *st, int is_add)
Definition: ssvm_eth.c:423
always_inline vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
static clib_error_t * ssvm_eth_init(vlib_main_t *vm)
Definition: ssvm_eth.c:182
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:373
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
unix_shared_memory_queue_t * unix_shared_memory_queue_init(int nels, int elsize, int consumer_pid, int signal_when_queue_non_empty)
u32 next_buffer
Next buffer for this linked-list of buffers.
Definition: buffer.h:112
static clib_error_t * ssvm_eth_interface_admin_up_down(vnet_main_t *vnm, u32 hw_if_index, u32 flags)
Definition: ssvm_eth.c:404
clib_error_t * ethernet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u8 *address, u32 *hw_if_index_return, ethernet_flag_change_function_t flag_change)
Definition: interface.c:157
u64 next_base_va
Definition: ssvm_eth.h:68
always_inline uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:919
u8 * name
Definition: ssvm.h:75
u8 data[SSVM_BUFFER_SIZE]
Definition: ssvm_eth.h:54
u64 uword
Definition: types.h:112
int unix_shared_memory_queue_add_raw(unix_shared_memory_queue_t *q, u8 *elem)
u32 total_length_not_including_first_buffer
Only valid for first buffer in chain.
Definition: buffer.h:106
ssvm_eth_tx_func_error_t
Definition: ssvm_eth.c:24
ssvm_eth_main_t ssvm_eth_main
Definition: ssvm_eth.c:17
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
unsigned char u8
Definition: types.h:56
u16 total_length_not_including_first_buffer
Definition: ssvm_eth.h:50
u8 data[0]
Packet data.
Definition: buffer.h:150
#define SSVM_PACKET_TYPE
Definition: ssvm_eth.h:39
#define CLIB_MEMORY_BARRIER()
Definition: clib.h:101
static clib_error_t * ssvm_config(vlib_main_t *vm, unformat_input_t *input)
Definition: ssvm_eth.c:137
#define clib_error_return(e, args...)
Definition: error.h:112
struct _unformat_input_t unformat_input_t
static u32 ssvm_eth_flag_change(vnet_main_t *vnm, vnet_hw_interface_t *hi, u32 flags)
Definition: ssvm_eth.c:455
u32 flags
Definition: vhost-user.h:73
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
#define foreach_ssvm_eth_tx_func_error
Definition: ssvm_eth.c:19
uword runtime_data[(128-1 *sizeof(vlib_node_function_t *)-1 *sizeof(vlib_error_t *)-11 *sizeof(u32)-5 *sizeof(u16))/sizeof(uword)]
Definition: node.h:432
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
int i_am_master
Definition: ssvm.h:77
struct _unix_shared_memory_queue unix_shared_memory_queue_t