memif: don't include prctl.h
[vpp.git] / src / plugins / memif / memif.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2017 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18
19 #define _GNU_SOURCE
20 #include <stdint.h>
21 #include <net/if.h>
22 #include <sys/types.h>
23 #include <fcntl.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/un.h>
27 #include <sys/uio.h>
28 #include <sys/mman.h>
29 #include <sys/eventfd.h>
30 #include <inttypes.h>
31 #include <limits.h>
32
33 #include <vlib/vlib.h>
34 #include <vlib/unix/unix.h>
35 #include <vnet/plugin/plugin.h>
36 #include <vnet/ethernet/ethernet.h>
37 #include <vnet/interface/rx_queue_funcs.h>
38 #include <vnet/interface/tx_queue_funcs.h>
39 #include <vpp/app/version.h>
40 #include <memif/memif.h>
41 #include <memif/private.h>
42
43 memif_main_t memif_main;
44
45 static u32
46 memif_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, u32 flags)
47 {
48   /* nothing for now */
49   return 0;
50 }
51
52 static clib_error_t *
53 memif_eth_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
54                               u32 flags)
55 {
56   /* nothing for now */
57   return 0;
58 }
59
60 static void
61 memif_queue_intfd_close (memif_queue_t * mq)
62 {
63   if (mq->int_clib_file_index != ~0)
64     {
65       memif_file_del_by_index (mq->int_clib_file_index);
66       mq->int_clib_file_index = ~0;
67       mq->int_fd = -1;
68     }
69   else if (mq->int_fd > -1)
70     {
71       close (mq->int_fd);
72       mq->int_fd = -1;
73     }
74 }
75
76 static void
77 memif_disconnect_free_zc_queue_buffer (memif_queue_t * mq, u8 is_rx)
78 {
79   vlib_main_t *vm = vlib_get_main ();
80   u16 ring_size, n_slots, mask, start;
81
82   ring_size = 1 << mq->log2_ring_size;
83   mask = ring_size - 1;
84   n_slots = mq->ring->head - mq->last_tail;
85   start = mq->last_tail & mask;
86   if (is_rx)
87     vlib_buffer_free_from_ring (vm, mq->buffers, start, ring_size, n_slots);
88   else
89     vlib_buffer_free_from_ring_no_next (vm, mq->buffers, start, ring_size,
90                                         n_slots);
91   vec_free (mq->buffers);
92 }
93
94 void
95 memif_disconnect (memif_if_t * mif, clib_error_t * err)
96 {
97   memif_main_t *mm = &memif_main;
98   vnet_main_t *vnm = vnet_get_main ();
99   memif_region_t *mr;
100   memif_queue_t *mq;
101   int i;
102   vlib_main_t *vm = vlib_get_main ();
103   int with_barrier = 0;
104
105   if (mif == 0)
106     return;
107
108   memif_log_debug (mif, "disconnect %u (%v)", mif->dev_instance,
109                    err ? err->what : 0);
110
111   if (err)
112     {
113       clib_error_t *e = 0;
114       mif->local_disc_string = vec_dup (err->what);
115       if (mif->sock && clib_socket_is_connected (mif->sock))
116         e = memif_msg_send_disconnect (mif, err);
117       clib_error_free (e);
118     }
119
120   /* set interface down */
121   mif->flags &= ~(MEMIF_IF_FLAG_CONNECTED | MEMIF_IF_FLAG_CONNECTING);
122   if (mif->hw_if_index != ~0)
123     vnet_hw_interface_set_flags (vnm, mif->hw_if_index, 0);
124
125   /* close connection socket */
126   if (mif->sock && mif->sock->fd)
127     {
128       memif_socket_file_t *msf = vec_elt_at_index (mm->socket_files,
129                                                    mif->socket_file_index);
130       hash_unset (msf->dev_instance_by_fd, mif->sock->fd);
131       memif_socket_close (&mif->sock);
132     }
133   else if (mif->sock)
134     {
135       clib_error_t *err;
136       err = clib_socket_close (mif->sock);
137       if (err)
138         {
139           memif_log_err (mif, "%U", format_clib_error, err);
140           clib_error_free (err);
141         }
142       clib_mem_free (mif->sock);
143     }
144
145   if (vlib_worker_thread_barrier_held () == 0)
146     {
147       with_barrier = 1;
148       vlib_worker_thread_barrier_sync (vm);
149     }
150
151   /* *INDENT-OFF* */
152   vec_foreach_index (i, mif->rx_queues)
153     {
154       mq = vec_elt_at_index (mif->rx_queues, i);
155       if (mq->ring)
156         {
157           if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
158           {
159             memif_disconnect_free_zc_queue_buffer(mq, 1);
160           }
161           mq->ring = 0;
162         }
163     }
164   vnet_hw_if_unregister_all_rx_queues (vnm, mif->hw_if_index);
165
166   /* *INDENT-OFF* */
167   vec_foreach_index (i, mif->tx_queues)
168   {
169     mq = vec_elt_at_index (mif->tx_queues, i);
170     if (mq->ring)
171     {
172       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
173       {
174         memif_disconnect_free_zc_queue_buffer(mq, 0);
175       }
176       clib_spinlock_free (&mq->lockp);
177     }
178     mq->ring = 0;
179   }
180   vnet_hw_if_unregister_all_tx_queues (vnm, mif->hw_if_index);
181   vnet_hw_if_update_runtime_data (vnm, mif->hw_if_index);
182
183   /* free tx and rx queues */
184   vec_foreach (mq, mif->rx_queues)
185     memif_queue_intfd_close (mq);
186   vec_free (mif->rx_queues);
187
188   vec_foreach (mq, mif->tx_queues)
189     memif_queue_intfd_close (mq);
190   vec_free (mif->tx_queues);
191
192   /* free memory regions */
193   vec_foreach (mr, mif->regions)
194     {
195       int rv;
196       if (mr->is_external)
197         continue;
198       if ((rv = munmap (mr->shm, mr->region_size)))
199         memif_log_err (mif, "munmap failed, rv = %d", rv);
200       if (mr->fd > -1)
201         close (mr->fd);
202     }
203   /* *INDENT-ON* */
204   vec_free (mif->regions);
205   vec_free (mif->remote_name);
206   vec_free (mif->remote_if_name);
207   clib_fifo_free (mif->msg_queue);
208
209   if (with_barrier)
210     vlib_worker_thread_barrier_release (vm);
211 }
212
213 static clib_error_t *
214 memif_int_fd_write_ready (clib_file_t * uf)
215 {
216   memif_main_t *mm = &memif_main;
217   u16 qid = uf->private_data & 0xFFFF;
218   memif_if_t *mif = vec_elt_at_index (mm->interfaces, uf->private_data >> 16);
219
220   memif_log_warn (mif, "unexpected EPOLLOUT on RX for queue %u", qid);
221   return 0;
222 }
223
224 static clib_error_t *
225 memif_int_fd_read_ready (clib_file_t * uf)
226 {
227   memif_main_t *mm = &memif_main;
228   vnet_main_t *vnm = vnet_get_main ();
229   u16 qid = uf->private_data & 0xFFFF;
230   memif_if_t *mif = vec_elt_at_index (mm->interfaces, uf->private_data >> 16);
231   memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, qid);
232   u64 b;
233   ssize_t size;
234
235   size = read (uf->file_descriptor, &b, sizeof (b));
236   if (size < 0)
237     {
238       memif_log_debug (mif, "Failed to read from socket");
239       return 0;
240     }
241
242   vnet_hw_if_rx_queue_set_int_pending (vnm, mq->queue_index);
243   mq->int_count++;
244
245   return 0;
246 }
247
248
249 clib_error_t *
250 memif_connect (memif_if_t * mif)
251 {
252   memif_main_t *mm = &memif_main;
253   vlib_main_t *vm = vlib_get_main ();
254   vnet_main_t *vnm = vnet_get_main ();
255   clib_file_t template = { 0 };
256   memif_region_t *mr;
257   int i, j;
258   u32 n_txqs = 0, n_threads = vlib_get_n_threads ();
259   clib_error_t *err = NULL;
260   u8 max_log2_ring_sz = 0;
261   int with_barrier = 0;
262
263   memif_log_debug (mif, "connect %u", mif->dev_instance);
264
265   vec_free (mif->local_disc_string);
266   vec_free (mif->remote_disc_string);
267
268   /* *INDENT-OFF* */
269   vec_foreach (mr, mif->regions)
270     {
271       if (mr->shm)
272         continue;
273
274       if (mr->fd < 0)
275         {
276           err = clib_error_return (0, "no memory region fd");
277           goto error;
278         }
279
280       if ((mr->shm = mmap (NULL, mr->region_size, PROT_READ | PROT_WRITE,
281                            MAP_SHARED, mr->fd, 0)) == MAP_FAILED)
282         {
283           err = clib_error_return_unix (0, "mmap");
284           goto error;
285         }
286     }
287   /* *INDENT-ON* */
288
289   template.read_function = memif_int_fd_read_ready;
290   template.write_function = memif_int_fd_write_ready;
291
292   with_barrier = 1;
293   if (vlib_worker_thread_barrier_held ())
294     with_barrier = 0;
295
296   if (with_barrier)
297     vlib_worker_thread_barrier_sync (vm);
298
299   /* *INDENT-OFF* */
300   vec_foreach_index (i, mif->tx_queues)
301     {
302       memif_queue_t *mq = vec_elt_at_index (mif->tx_queues, i);
303       max_log2_ring_sz = clib_max (max_log2_ring_sz, mq->log2_ring_size);
304
305       mq->ring = mif->regions[mq->region].shm + mq->offset;
306       if (mq->ring->cookie != MEMIF_COOKIE)
307         {
308           err = clib_error_return (0, "wrong cookie on tx ring %u", i);
309           goto error;
310         }
311       mq->queue_index =
312         vnet_hw_if_register_tx_queue (vnm, mif->hw_if_index, i);
313       clib_spinlock_init (&mq->lockp);
314
315       if (mif->flags & MEMIF_IF_FLAG_USE_DMA)
316         {
317           memif_dma_info_t *dma_info;
318           mq->dma_head = 0;
319           mq->dma_tail = 0;
320           mq->dma_info_head = 0;
321           mq->dma_info_tail = 0;
322           mq->dma_info_size = MEMIF_DMA_INFO_SIZE;
323           vec_validate_aligned (mq->dma_info, MEMIF_DMA_INFO_SIZE,
324                                 CLIB_CACHE_LINE_BYTES);
325
326           vec_foreach (dma_info, mq->dma_info)
327             {
328               vec_validate_aligned (dma_info->data.desc_data,
329                                     pow2_mask (max_log2_ring_sz),
330                                     CLIB_CACHE_LINE_BYTES);
331               vec_validate_aligned (dma_info->data.desc_len,
332                                     pow2_mask (max_log2_ring_sz),
333                                     CLIB_CACHE_LINE_BYTES);
334               vec_validate_aligned (dma_info->data.desc_status,
335                                     pow2_mask (max_log2_ring_sz),
336                                     CLIB_CACHE_LINE_BYTES);
337               vec_validate_aligned (dma_info->data.copy_ops, 0,
338                                     CLIB_CACHE_LINE_BYTES);
339               vec_reset_length (dma_info->data.copy_ops);
340               vec_validate_aligned (dma_info->data.buffers, 0,
341                                     CLIB_CACHE_LINE_BYTES);
342               vec_reset_length (dma_info->data.buffers);
343             }
344         }
345     }
346
347   if (vec_len (mif->tx_queues) > 0)
348     {
349       n_txqs = vec_len (mif->tx_queues);
350       for (j = 0; j < n_threads; j++)
351         {
352           u32 qi = mif->tx_queues[j % n_txqs].queue_index;
353           vnet_hw_if_tx_queue_assign_thread (vnm, qi, j);
354         }
355     }
356
357   vec_foreach_index (i, mif->rx_queues)
358     {
359       memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, i);
360       u32 ti;
361       u32 qi;
362       int rv;
363
364       max_log2_ring_sz = clib_max (max_log2_ring_sz, mq->log2_ring_size);
365
366       mq->ring = mif->regions[mq->region].shm + mq->offset;
367       if (mq->ring->cookie != MEMIF_COOKIE)
368         {
369           err = clib_error_return (0, "wrong cookie on tx ring %u", i);
370           goto error;
371         }
372       qi = vnet_hw_if_register_rx_queue (vnm, mif->hw_if_index, i,
373                                          VNET_HW_IF_RXQ_THREAD_ANY);
374       mq->queue_index = qi;
375
376       if (mif->flags & MEMIF_IF_FLAG_USE_DMA)
377         {
378           memif_dma_info_t *dma_info;
379           mq->dma_head = 0;
380           mq->dma_tail = 0;
381           mq->dma_info_head = 0;
382           mq->dma_info_tail = 0;
383           mq->dma_info_size = MEMIF_DMA_INFO_SIZE;
384           vec_validate_aligned (mq->dma_info, MEMIF_DMA_INFO_SIZE,
385                                 CLIB_CACHE_LINE_BYTES);
386           vec_foreach (dma_info, mq->dma_info)
387             {
388               vec_validate_aligned (dma_info->data.desc_data,
389                                     pow2_mask (max_log2_ring_sz),
390                                     CLIB_CACHE_LINE_BYTES);
391               vec_validate_aligned (dma_info->data.desc_len,
392                                     pow2_mask (max_log2_ring_sz),
393                                     CLIB_CACHE_LINE_BYTES);
394               vec_validate_aligned (dma_info->data.desc_status,
395                                     pow2_mask (max_log2_ring_sz),
396                                     CLIB_CACHE_LINE_BYTES);
397               vec_validate_aligned (dma_info->data.copy_ops, 0,
398                                     CLIB_CACHE_LINE_BYTES);
399               vec_reset_length (dma_info->data.copy_ops);
400               vec_validate_aligned (dma_info->data.buffers, 0,
401                                     CLIB_CACHE_LINE_BYTES);
402               vec_reset_length (dma_info->data.buffers);
403             }
404         }
405
406       if (mq->int_fd > -1)
407         {
408           template.file_descriptor = mq->int_fd;
409           template.private_data = (mif->dev_instance << 16) | (i & 0xFFFF);
410           template.description = format (0, "%U rx %u int",
411                                          format_memif_device_name,
412                                          mif->dev_instance, i);
413           memif_file_add (&mq->int_clib_file_index, &template);
414           vnet_hw_if_set_rx_queue_file_index (vnm, qi,
415                                               mq->int_clib_file_index);
416         }
417       ti = vnet_hw_if_get_rx_queue_thread_index (vnm, qi);
418       mq->buffer_pool_index = vlib_buffer_pool_get_default_for_numa (
419         vm, vlib_get_main_by_index (ti)->numa_node);
420       rv = vnet_hw_if_set_rx_queue_mode (vnm, qi, VNET_HW_IF_RX_MODE_DEFAULT);
421       vnet_hw_if_update_runtime_data (vnm, mif->hw_if_index);
422
423       if (rv)
424         memif_log_err
425           (mif, "Warning: unable to set rx mode for interface %d queue %d: "
426            "rc=%d", mif->hw_if_index, i, rv);
427       else
428         {
429           vnet_hw_if_rx_mode rxmode = vnet_hw_if_get_rx_queue_mode (vnm, qi);
430
431           if (rxmode == VNET_HW_IF_RX_MODE_POLLING)
432             mq->ring->flags |= MEMIF_RING_FLAG_MASK_INT;
433           else
434             vnet_hw_if_rx_queue_set_int_pending (vnm, qi);
435         }
436     }
437   /* *INDENT-ON* */
438
439   if (1 << max_log2_ring_sz > vec_len (mm->per_thread_data[0].desc_data))
440     {
441       memif_per_thread_data_t *ptd;
442
443       vec_foreach (ptd, mm->per_thread_data)
444         {
445           vec_validate_aligned (ptd->desc_data, pow2_mask (max_log2_ring_sz),
446                                 CLIB_CACHE_LINE_BYTES);
447           vec_validate_aligned (ptd->desc_len, pow2_mask (max_log2_ring_sz),
448                                 CLIB_CACHE_LINE_BYTES);
449           vec_validate_aligned (ptd->desc_status, pow2_mask (max_log2_ring_sz),
450                                 CLIB_CACHE_LINE_BYTES);
451         }
452     }
453   if (with_barrier)
454     vlib_worker_thread_barrier_release (vm);
455
456   mif->flags &= ~MEMIF_IF_FLAG_CONNECTING;
457   mif->flags |= MEMIF_IF_FLAG_CONNECTED;
458
459   vnet_hw_interface_set_flags (vnm, mif->hw_if_index,
460                                VNET_HW_INTERFACE_FLAG_LINK_UP);
461   return 0;
462
463 error:
464   if (with_barrier)
465     vlib_worker_thread_barrier_release (vm);
466   memif_log_err (mif, "%U", format_clib_error, err);
467   return err;
468 }
469
470 static_always_inline memif_ring_t *
471 memif_get_ring (memif_if_t * mif, memif_ring_type_t type, u16 ring_num)
472 {
473   if (vec_len (mif->regions) == 0)
474     return NULL;
475   void *p = mif->regions[0].shm;
476   int ring_size =
477     sizeof (memif_ring_t) +
478     sizeof (memif_desc_t) * (1 << mif->run.log2_ring_size);
479   p += (ring_num + type * mif->run.num_s2m_rings) * ring_size;
480
481   return (memif_ring_t *) p;
482 }
483
484 clib_error_t *
485 memif_init_regions_and_queues (memif_if_t * mif)
486 {
487   vlib_main_t *vm = vlib_get_main ();
488   memif_socket_file_t *msf;
489   memif_ring_t *ring = NULL;
490   int fd, i, j;
491   u64 buffer_offset;
492   memif_region_t *r;
493   clib_error_t *err;
494
495   ASSERT (vec_len (mif->regions) == 0);
496   vec_add2_aligned (mif->regions, r, 1, CLIB_CACHE_LINE_BYTES);
497
498   buffer_offset = (mif->run.num_s2m_rings + mif->run.num_m2s_rings) *
499     (sizeof (memif_ring_t) +
500      sizeof (memif_desc_t) * (1 << mif->run.log2_ring_size));
501
502   r->region_size = buffer_offset;
503
504   if ((mif->flags & MEMIF_IF_FLAG_ZERO_COPY) == 0)
505     r->region_size += mif->run.buffer_size * (1 << mif->run.log2_ring_size) *
506       (mif->run.num_s2m_rings + mif->run.num_m2s_rings);
507
508   if ((fd = clib_mem_vm_create_fd (CLIB_MEM_PAGE_SZ_DEFAULT, "%U region 0",
509                                    format_memif_device_name,
510                                    mif->dev_instance)) == -1)
511     {
512       err = clib_mem_get_last_error ();
513       goto error;
514     }
515
516   if ((ftruncate (fd, r->region_size)) == -1)
517     {
518       err = clib_error_return_unix (0, "ftruncate");
519       goto error;
520     }
521
522   msf = pool_elt_at_index (memif_main.socket_files, mif->socket_file_index);
523   r->shm = clib_mem_vm_map_shared (0, r->region_size, fd, 0, "memif%lu/%lu:0",
524                                    msf->socket_id, mif->id);
525
526   if (r->shm == CLIB_MEM_VM_MAP_FAILED)
527     {
528       err = clib_error_return_unix (0, "memif shared region map failed");
529       goto error;
530     }
531
532   r->fd = fd;
533
534   if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
535     {
536       vlib_buffer_pool_t *bp;
537       /* *INDENT-OFF* */
538       vec_foreach (bp, vm->buffer_main->buffer_pools)
539         {
540           vlib_physmem_map_t *pm;
541           pm = vlib_physmem_get_map (vm, bp->physmem_map_index);
542           vec_add2_aligned (mif->regions, r, 1, CLIB_CACHE_LINE_BYTES);
543           r->fd = pm->fd;
544           r->region_size = pm->n_pages << pm->log2_page_size;
545           r->shm = pm->base;
546           r->is_external = 1;
547         }
548       /* *INDENT-ON* */
549     }
550
551   for (i = 0; i < mif->run.num_s2m_rings; i++)
552     {
553       ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
554       ring->head = ring->tail = 0;
555       ring->cookie = MEMIF_COOKIE;
556
557       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
558         continue;
559
560       for (j = 0; j < (1 << mif->run.log2_ring_size); j++)
561         {
562           u16 slot = i * (1 << mif->run.log2_ring_size) + j;
563           ring->desc[j].region = 0;
564           ring->desc[j].offset =
565             buffer_offset + (u32) (slot * mif->run.buffer_size);
566           ring->desc[j].length = mif->run.buffer_size;
567         }
568     }
569   for (i = 0; i < mif->run.num_m2s_rings; i++)
570     {
571       ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
572       ring->head = ring->tail = 0;
573       ring->cookie = MEMIF_COOKIE;
574
575       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
576         continue;
577
578       for (j = 0; j < (1 << mif->run.log2_ring_size); j++)
579         {
580           u16 slot =
581             (i + mif->run.num_s2m_rings) * (1 << mif->run.log2_ring_size) + j;
582           ring->desc[j].region = 0;
583           ring->desc[j].offset =
584             buffer_offset + (u32) (slot * mif->run.buffer_size);
585           ring->desc[j].length = mif->run.buffer_size;
586         }
587     }
588
589   ASSERT (mif->tx_queues == 0);
590   vec_validate_aligned (mif->tx_queues, mif->run.num_s2m_rings - 1,
591                         CLIB_CACHE_LINE_BYTES);
592
593   /* *INDENT-OFF* */
594   vec_foreach_index (i, mif->tx_queues)
595     {
596       memif_queue_t *mq = vec_elt_at_index (mif->tx_queues, i);
597       if ((mq->int_fd = eventfd (0, EFD_NONBLOCK)) < 0)
598         {
599           err = clib_error_return_unix (0, "eventfd[tx queue %u]", i);
600           goto error;
601         }
602
603       mq->int_clib_file_index = ~0;
604       mq->ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
605       mq->log2_ring_size = mif->cfg.log2_ring_size;
606       mq->region = 0;
607       mq->offset = (void *) mq->ring - (void *) mif->regions[mq->region].shm;
608       mq->last_head = 0;
609       mq->type = MEMIF_RING_S2M;
610       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
611         vec_validate_aligned (mq->buffers, 1 << mq->log2_ring_size,
612                               CLIB_CACHE_LINE_BYTES);
613     }
614   /* *INDENT-ON* */
615
616   ASSERT (mif->rx_queues == 0);
617   vec_validate_aligned (mif->rx_queues, mif->run.num_m2s_rings - 1,
618                         CLIB_CACHE_LINE_BYTES);
619
620   /* *INDENT-OFF* */
621   vec_foreach_index (i, mif->rx_queues)
622     {
623       memif_queue_t *mq = vec_elt_at_index (mif->rx_queues, i);
624       if ((mq->int_fd = eventfd (0, EFD_NONBLOCK)) < 0)
625         {
626           err = clib_error_return_unix (0, "eventfd[rx queue %u]", i);
627           goto error;
628         }
629       mq->int_clib_file_index = ~0;
630       mq->ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
631       mq->log2_ring_size = mif->cfg.log2_ring_size;
632       mq->region = 0;
633       mq->offset = (void *) mq->ring - (void *) mif->regions[mq->region].shm;
634       mq->last_head = 0;
635       mq->type = MEMIF_RING_M2S;
636       if (mif->flags & MEMIF_IF_FLAG_ZERO_COPY)
637         vec_validate_aligned (mq->buffers, 1 << mq->log2_ring_size,
638                               CLIB_CACHE_LINE_BYTES);
639     }
640   /* *INDENT-ON* */
641
642   return 0;
643
644 error:
645   memif_log_err (mif, "%U", format_clib_error, err);
646   return err;
647 }
648
649 static uword
650 memif_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
651 {
652   memif_main_t *mm = &memif_main;
653   memif_if_t *mif;
654   clib_socket_t *sock;
655   uword *event_data = 0, event_type;
656   u8 enabled = 0;
657   f64 start_time, last_run_duration = 0, now;
658   clib_error_t *err;
659
660   sock = clib_mem_alloc (sizeof (clib_socket_t));
661   clib_memset (sock, 0, sizeof (clib_socket_t));
662
663   while (1)
664     {
665       if (enabled)
666         vlib_process_wait_for_event_or_clock (vm, (f64) 3 -
667                                               last_run_duration);
668       else
669         vlib_process_wait_for_event (vm);
670
671       event_type = vlib_process_get_events (vm, &event_data);
672       vec_reset_length (event_data);
673
674       switch (event_type)
675         {
676         case ~0:
677           break;
678         case MEMIF_PROCESS_EVENT_START:
679           enabled = 1;
680           break;
681         case MEMIF_PROCESS_EVENT_STOP:
682           enabled = 0;
683           continue;
684         case MEMIF_PROCESS_EVENT_ADMIN_UP_DOWN:
685           break;
686         default:
687           ASSERT (0);
688         }
689
690       last_run_duration = start_time = vlib_time_now (vm);
691       /* *INDENT-OFF* */
692       pool_foreach (mif, mm->interfaces)
693          {
694           memif_socket_file_t * msf = vec_elt_at_index (mm->socket_files, mif->socket_file_index);
695           /* Allow no more than 10us without a pause */
696           now = vlib_time_now (vm);
697           if (now > start_time + 10e-6)
698             {
699               vlib_process_suspend (vm, 100e-6);        /* suspend for 100 us */
700               start_time = vlib_time_now (vm);
701             }
702
703           if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) == 0)
704             continue;
705
706           if (mif->flags & MEMIF_IF_FLAG_CONNECTING)
707             continue;
708
709           if (mif->flags & MEMIF_IF_FLAG_CONNECTED)
710             continue;
711
712           if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
713             {
714               clib_memset (sock, 0, sizeof(clib_socket_t));
715               sock->config = (char *) msf->filename;
716               sock->is_seqpacket = 1;
717               sock->is_blocking = 1;
718
719               if ((err = clib_socket_init (sock)))
720                 {
721                   clib_error_free (err);
722                 }
723               else
724                 {
725                   clib_file_t t = { 0 };
726
727                   t.read_function = memif_slave_conn_fd_read_ready;
728                   t.write_function = memif_slave_conn_fd_write_ready;
729                   t.error_function = memif_slave_conn_fd_error;
730                   t.file_descriptor = sock->fd;
731                   t.private_data = mif->dev_instance;
732                   memif_file_add (&sock->private_data, &t);
733                   t.description = format (0, "%U ctl",
734                                           format_memif_device_name,
735                                           mif->dev_instance);
736                   hash_set (msf->dev_instance_by_fd, sock->fd, mif->dev_instance);
737
738                   mif->flags |= MEMIF_IF_FLAG_CONNECTING;
739                   mif->sock = sock;
740                   sock = clib_mem_alloc (sizeof(clib_socket_t));
741                 }
742             }
743         }
744       /* *INDENT-ON* */
745       last_run_duration = vlib_time_now (vm) - last_run_duration;
746     }
747   return 0;
748 }
749
750 VLIB_REGISTER_NODE (memif_process_node,static) = {
751   .function = memif_process,
752   .type = VLIB_NODE_TYPE_PROCESS,
753   .name = "memif-process",
754 };
755
756 /*
757  * Returns an unused socket id, and ~0 if it can't find one.
758  */
759 u32
760 memif_get_unused_socket_id ()
761 {
762   memif_main_t *mm = &memif_main;
763   uword *p;
764   int i, j;
765
766   static u32 seed = 0;
767   /* limit to 1M tries */
768   for (j = 0; j < 1 << 10; j++)
769     {
770       seed = random_u32 (&seed);
771       for (i = 0; i < 1 << 10; i++)
772         {
773           /* look around randomly generated id */
774           seed += (2 * (i % 2) - 1) * i;
775           if (seed == (u32) ~0)
776             continue;
777           p = hash_get (mm->socket_file_index_by_sock_id, seed);
778           if (!p)
779             return seed;
780         }
781     }
782
783   return ~0;
784 }
785
786 clib_error_t *
787 memif_socket_filename_add_del (u8 is_add, u32 sock_id, char *sock_filename)
788 {
789   memif_main_t *mm = &memif_main;
790   uword *p;
791   memif_socket_file_t *msf;
792   clib_error_t *err = 0;
793   char *dir = 0, *tmp;
794   u32 idx = 0;
795   u8 *name = 0;
796
797   /* allow adding socket id 0 */
798   if (sock_id == 0 && is_add == 0)
799     return vnet_error (VNET_ERR_INVALID_ARGUMENT, "cannot delete socket id 0");
800
801   if (sock_id == ~0)
802     return vnet_error (VNET_ERR_INVALID_ARGUMENT,
803                        "socked id is not specified");
804
805   if (is_add == 0)
806     {
807       p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
808       if (!p)
809         /* Don't delete non-existent entries. */
810         return vnet_error (VNET_ERR_INVALID_ARGUMENT,
811                            "socket file with id %u does not exist", sock_id);
812
813       msf = pool_elt_at_index (mm->socket_files, *p);
814       if (msf->ref_cnt > 0)
815         return vnet_error (VNET_ERR_UNEXPECTED_INTF_STATE,
816                            "socket file '%s' is in use", msf->filename);
817
818       vec_free (msf->filename);
819       pool_put (mm->socket_files, msf);
820
821       hash_unset (mm->socket_file_index_by_sock_id, sock_id);
822
823       return 0;
824     }
825
826   if (sock_filename == 0 || sock_filename[0] == 0)
827     return vnet_error (VNET_ERR_INVALID_ARGUMENT,
828                        "socket filename not specified");
829
830   if (clib_socket_prefix_is_valid (sock_filename))
831     {
832       name = format (0, "%s%c", sock_filename, 0);
833     }
834   else if (sock_filename[0] == '/')
835     {
836       name = format (0, "%s%c", sock_filename, 0);
837     }
838   else
839     {
840       /* copy runtime dir path */
841       vec_add (dir, vlib_unix_get_runtime_dir (),
842                strlen (vlib_unix_get_runtime_dir ()));
843       vec_add1 (dir, '/');
844
845       /* if sock_filename contains dirs, add them to path */
846       tmp = strrchr (sock_filename, '/');
847       if (tmp)
848         {
849           idx = tmp - sock_filename;
850           vec_add (dir, sock_filename, idx);
851         }
852
853       vec_add1 (dir, '\0');
854       /* create socket dir */
855       if ((err = vlib_unix_recursive_mkdir (dir)))
856         {
857           clib_error_free (err);
858           err = vnet_error (VNET_ERR_SYSCALL_ERROR_1,
859                             "unable to create socket dir");
860           goto done;
861         }
862
863       name =
864         format (0, "%s/%s%c", vlib_unix_get_runtime_dir (), sock_filename, 0);
865     }
866
867   p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
868   if (p)
869     {
870       msf = pool_elt_at_index (mm->socket_files, *p);
871       if (strcmp ((char *) msf->filename, (char *) name) == 0)
872         {
873           /* Silently accept identical "add". */
874           goto done;
875         }
876
877       /* But don't allow a direct add of a different filename. */
878       err = vnet_error (VNET_ERR_ENTRY_ALREADY_EXISTS, "entry already exists");
879       goto done;
880     }
881
882   pool_get (mm->socket_files, msf);
883   clib_memset (msf, 0, sizeof (memif_socket_file_t));
884
885   msf->filename = name;
886   msf->socket_id = sock_id;
887   name = 0;
888
889   hash_set (mm->socket_file_index_by_sock_id, sock_id, msf - mm->socket_files);
890
891 done:
892   vec_free (name);
893   vec_free (dir);
894   return err;
895 }
896
897 clib_error_t *
898 memif_delete_if (vlib_main_t *vm, memif_if_t *mif)
899 {
900   vnet_main_t *vnm = vnet_get_main ();
901   memif_main_t *mm = &memif_main;
902   memif_socket_file_t *msf =
903     vec_elt_at_index (mm->socket_files, mif->socket_file_index);
904   clib_error_t *err;
905
906   mif->flags |= MEMIF_IF_FLAG_DELETING;
907   vec_free (mif->local_disc_string);
908   vec_free (mif->remote_disc_string);
909
910   /* bring down the interface */
911   vnet_hw_interface_set_flags (vnm, mif->hw_if_index, 0);
912   vnet_sw_interface_set_flags (vnm, mif->sw_if_index, 0);
913
914   err = clib_error_return (0, "interface deleted");
915   memif_disconnect (mif, err);
916   clib_error_free (err);
917
918   if (mif->hw_if_index != ~0)
919     {
920       /* remove the interface */
921       if (mif->mode == MEMIF_INTERFACE_MODE_IP)
922         vnet_delete_hw_interface (vnm, mif->hw_if_index);
923       else
924         ethernet_delete_interface (vnm, mif->hw_if_index);
925       mif->hw_if_index = ~0;
926     }
927
928   /* free interface data structures */
929   mhash_unset (&msf->dev_instance_by_id, &mif->id, 0);
930
931   /* remove socket file */
932   if (--(msf->ref_cnt) == 0)
933     {
934       if (msf->is_listener)
935         {
936           int i;
937           /* *INDENT-OFF* */
938           vec_foreach_index (i, msf->pending_clients)
939             memif_socket_close (msf->pending_clients + i);
940           /* *INDENT-ON* */
941           memif_socket_close (&msf->sock);
942           vec_free (msf->pending_clients);
943         }
944       mhash_free (&msf->dev_instance_by_id);
945       hash_free (msf->dev_instance_by_fd);
946       if (msf->sock)
947         {
948           err = clib_socket_close (msf->sock);
949           if (err)
950             {
951               memif_log_err (mif, "%U", format_clib_error, err);
952               clib_error_free (err);
953             }
954           clib_mem_free (msf->sock);
955         }
956     }
957
958   vec_free (mif->local_disc_string);
959   clib_memset (mif, 0, sizeof (*mif));
960   pool_put (mm->interfaces, mif);
961
962   if (pool_elts (mm->interfaces) == 0)
963     vlib_process_signal_event (vm, memif_process_node.index,
964                                MEMIF_PROCESS_EVENT_STOP, 0);
965
966   return 0;
967 }
968
969 /* *INDENT-OFF* */
970 VNET_HW_INTERFACE_CLASS (memif_ip_hw_if_class, static) = {
971   .name = "memif-ip",
972   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
973   .tx_hash_fn_type = VNET_HASH_FN_TYPE_IP,
974 };
975 /* *INDENT-ON* */
976
977 static void
978 memif_prepare_dma_args (vlib_dma_config_t *args)
979 {
980   args->max_batches = 256;
981   args->max_transfer_size = VLIB_BUFFER_DEFAULT_DATA_SIZE;
982   args->barrier_before_last = 1;
983   args->sw_fallback = 1;
984   args->callback_fn = NULL;
985 }
986
987 clib_error_t *
988 memif_create_if (vlib_main_t *vm, memif_create_if_args_t *args)
989 {
990   memif_main_t *mm = &memif_main;
991   vlib_thread_main_t *tm = vlib_get_thread_main ();
992   vnet_main_t *vnm = vnet_get_main ();
993   vnet_eth_interface_registration_t eir = {};
994   memif_if_t *mif = 0;
995   vnet_sw_interface_t *sw;
996   uword *p;
997   memif_socket_file_t *msf = 0;
998   clib_error_t *err = 0;
999
1000   p = hash_get (mm->socket_file_index_by_sock_id, args->socket_id);
1001   if (p == 0)
1002     {
1003       err = vnet_error (VNET_ERR_INVALID_ARGUMENT, "unknown socket id");
1004       goto done;
1005     }
1006
1007   msf = vec_elt_at_index (mm->socket_files, p[0]);
1008
1009   /* existing socket file can be either master or slave but cannot be both */
1010   if (msf->ref_cnt > 0)
1011     {
1012       if ((!msf->is_listener != !args->is_master))
1013         {
1014           err =
1015             vnet_error (VNET_ERR_SUBIF_ALREADY_EXISTS,
1016                         "socket file cannot be used by both master and slave");
1017           goto done;
1018         }
1019
1020       p = mhash_get (&msf->dev_instance_by_id, &args->id);
1021       if (p)
1022         {
1023           err = vnet_error (VNET_ERR_SUBIF_ALREADY_EXISTS,
1024                             "interface already exists");
1025           goto done;
1026         }
1027     }
1028
1029   /* Create new socket file */
1030   if (msf->ref_cnt == 0)
1031     {
1032       mhash_init (&msf->dev_instance_by_id, sizeof (uword),
1033                   sizeof (memif_interface_id_t));
1034       msf->dev_instance_by_fd = hash_create (0, sizeof (uword));
1035       msf->is_listener = (args->is_master != 0);
1036
1037       memif_log_debug (0, "initializing socket file %s", msf->filename);
1038     }
1039
1040   if (mm->per_thread_data == 0)
1041     {
1042       int i;
1043
1044       vec_validate_aligned (mm->per_thread_data, tm->n_vlib_mains - 1,
1045                             CLIB_CACHE_LINE_BYTES);
1046
1047       for (i = 0; i < tm->n_vlib_mains; i++)
1048         {
1049           memif_per_thread_data_t *ptd =
1050             vec_elt_at_index (mm->per_thread_data, i);
1051           vlib_buffer_t *bt = &ptd->buffer_template;
1052           clib_memset (bt, 0, sizeof (vlib_buffer_t));
1053           bt->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID;
1054           bt->total_length_not_including_first_buffer = 0;
1055           vnet_buffer (bt)->sw_if_index[VLIB_TX] = (u32) ~ 0;
1056
1057           vec_validate_aligned (ptd->copy_ops, 0, CLIB_CACHE_LINE_BYTES);
1058           vec_reset_length (ptd->copy_ops);
1059           vec_validate_aligned (ptd->buffers, 0, CLIB_CACHE_LINE_BYTES);
1060           vec_reset_length (ptd->buffers);
1061         }
1062     }
1063
1064   pool_get (mm->interfaces, mif);
1065   clib_memset (mif, 0, sizeof (*mif));
1066   mif->dev_instance = mif - mm->interfaces;
1067   mif->socket_file_index = msf - mm->socket_files;
1068   mif->id = args->id;
1069   mif->sw_if_index = mif->hw_if_index = mif->per_interface_next_index = ~0;
1070   mif->mode = args->mode;
1071   if (args->secret)
1072     mif->secret = vec_dup (args->secret);
1073
1074   /* register dma config if enabled */
1075   if (args->use_dma)
1076     {
1077       vlib_dma_config_t dma_args;
1078       bzero (&dma_args, sizeof (dma_args));
1079       memif_prepare_dma_args (&dma_args);
1080
1081       dma_args.max_transfers = 1 << args->log2_ring_size;
1082       dma_args.callback_fn = memif_dma_completion_cb;
1083       mif->dma_input_config = vlib_dma_config_add (vm, &dma_args);
1084       dma_args.callback_fn = memif_tx_dma_completion_cb;
1085       mif->dma_tx_config = vlib_dma_config_add (vm, &dma_args);
1086     }
1087
1088   if (mif->mode == MEMIF_INTERFACE_MODE_ETHERNET)
1089     {
1090
1091       if (!args->hw_addr_set)
1092         {
1093           f64 now = vlib_time_now (vm);
1094           u32 rnd;
1095           rnd = (u32) (now * 1e6);
1096           rnd = random_u32 (&rnd);
1097
1098           memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
1099           args->hw_addr[0] = 2;
1100           args->hw_addr[1] = 0xfe;
1101         }
1102
1103       eir.dev_class_index = memif_device_class.index;
1104       eir.dev_instance = mif->dev_instance;
1105       eir.address = args->hw_addr;
1106       eir.cb.flag_change = memif_eth_flag_change;
1107       eir.cb.set_max_frame_size = memif_eth_set_max_frame_size;
1108       mif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
1109     }
1110   else if (mif->mode == MEMIF_INTERFACE_MODE_IP)
1111     {
1112       mif->hw_if_index =
1113         vnet_register_interface (vnm, memif_device_class.index,
1114                                  mif->dev_instance,
1115                                  memif_ip_hw_if_class.index,
1116                                  mif->dev_instance);
1117     }
1118   else
1119     {
1120       err =
1121         vnet_error (VNET_ERR_SYSCALL_ERROR_2, "unsupported interface mode");
1122       goto error;
1123     }
1124
1125   sw = vnet_get_hw_sw_interface (vnm, mif->hw_if_index);
1126   mif->sw_if_index = sw->sw_if_index;
1127
1128   mif->cfg.log2_ring_size = args->log2_ring_size;
1129   mif->cfg.buffer_size = args->buffer_size;
1130   mif->cfg.num_s2m_rings =
1131     args->is_master ? args->rx_queues : args->tx_queues;
1132   mif->cfg.num_m2s_rings =
1133     args->is_master ? args->tx_queues : args->rx_queues;
1134
1135   args->sw_if_index = mif->sw_if_index;
1136
1137   /* If this is new one, start listening */
1138   if (msf->is_listener && msf->ref_cnt == 0)
1139     {
1140       clib_socket_t *s = clib_mem_alloc (sizeof (clib_socket_t));
1141
1142       ASSERT (msf->sock == 0);
1143       msf->sock = s;
1144
1145       clib_memset (s, 0, sizeof (clib_socket_t));
1146       s->config = (char *) msf->filename;
1147       s->local_only = 1;
1148       s->is_server = 1;
1149       s->allow_group_write = 1;
1150       s->is_seqpacket = 1;
1151       s->passcred = 1;
1152
1153       if ((err = clib_socket_init (s)))
1154         {
1155           err->code = VNET_ERR_SYSCALL_ERROR_4;
1156           goto error;
1157         }
1158
1159       clib_file_t template = { 0 };
1160       template.read_function = memif_conn_fd_accept_ready;
1161       template.file_descriptor = msf->sock->fd;
1162       template.private_data = mif->socket_file_index;
1163       template.description = format (0, "memif listener %s", msf->filename);
1164       memif_file_add (&msf->sock->private_data, &template);
1165     }
1166
1167   msf->ref_cnt++;
1168
1169   if (args->is_master == 0)
1170     {
1171       mif->flags |= MEMIF_IF_FLAG_IS_SLAVE;
1172       if (args->is_zero_copy)
1173         mif->flags |= MEMIF_IF_FLAG_ZERO_COPY;
1174     }
1175
1176   if (args->use_dma)
1177     mif->flags |= MEMIF_IF_FLAG_USE_DMA;
1178
1179   vnet_hw_if_set_caps (vnm, mif->hw_if_index, VNET_HW_IF_CAP_INT_MODE);
1180   vnet_hw_if_set_input_node (vnm, mif->hw_if_index, memif_input_node.index);
1181   mhash_set (&msf->dev_instance_by_id, &mif->id, mif->dev_instance, 0);
1182
1183   if (pool_elts (mm->interfaces) == 1)
1184     {
1185       vlib_process_signal_event (vm, memif_process_node.index,
1186                                  MEMIF_PROCESS_EVENT_START, 0);
1187     }
1188   goto done;
1189
1190 error:
1191   memif_delete_if (vm, mif);
1192   if (err)
1193     memif_log_err (mif, "%U", format_clib_error, err);
1194   return err;
1195
1196 done:
1197   return err;
1198 }
1199
1200 clib_error_t *
1201 memif_interface_admin_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags)
1202 {
1203   memif_main_t *mm = &memif_main;
1204   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
1205   memif_if_t *mif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
1206   static clib_error_t *error = 0;
1207
1208   if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
1209     {
1210       if (mif->flags & MEMIF_IF_FLAG_CONNECTED)
1211         {
1212           vnet_hw_interface_set_flags (vnm, mif->hw_if_index,
1213                                        VNET_HW_INTERFACE_FLAG_LINK_UP);
1214         }
1215       mif->flags |= MEMIF_IF_FLAG_ADMIN_UP;
1216     }
1217   else
1218     mif->flags &= ~MEMIF_IF_FLAG_ADMIN_UP;
1219
1220   vlib_process_signal_event (vnm->vlib_main, memif_process_node.index,
1221                              MEMIF_PROCESS_EVENT_ADMIN_UP_DOWN, 0);
1222   return error;
1223 }
1224
1225 static clib_error_t *
1226 memif_init (vlib_main_t * vm)
1227 {
1228   memif_main_t *mm = &memif_main;
1229
1230   clib_memset (mm, 0, sizeof (memif_main_t));
1231
1232   mm->log_class = vlib_log_register_class ("memif_plugin", 0);
1233   memif_log_debug (0, "initialized");
1234
1235   /* initialize binary API */
1236   memif_plugin_api_hookup (vm);
1237
1238   /*
1239    * Pre-stuff socket filename pool with a non-modifieable mapping
1240    * for socket-id 0 to MEMIF_DEFAULT_SOCKET_FILENAME in the
1241    * default run-time directory.
1242    */
1243   return memif_socket_filename_add_del (1, 0, MEMIF_DEFAULT_SOCKET_FILENAME);
1244 }
1245
1246 VLIB_INIT_FUNCTION (memif_init);
1247
1248 /* *INDENT-OFF* */
1249 VLIB_PLUGIN_REGISTER () = {
1250     .version = VPP_BUILD_VER,
1251     .description = "Packet Memory Interface (memif) -- Experimental",
1252 };
1253 /* *INDENT-ON* */
1254
1255 /*
1256  * fd.io coding-style-patch-verification: ON
1257  *
1258  * Local Variables:
1259  * eval: (c-set-style "gnu")
1260  * End:
1261  */