a671bda51f7164167b759a7939b90b61236b89ff
[vpp.git] / src / plugins / memif / memif.c
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2016 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 #define _GNU_SOURCE
19 #include <stdint.h>
20 #include <net/if.h>
21 #include <sys/types.h>
22 #include <fcntl.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26 #include <sys/uio.h>
27 #include <sys/mman.h>
28 #include <sys/prctl.h>
29 #include <inttypes.h>
30
31 #include <vlib/vlib.h>
32 #include <vlib/unix/unix.h>
33 #include <vnet/plugin/plugin.h>
34 #include <vnet/ethernet/ethernet.h>
35 #include <vpp/app/version.h>
36 #include <memif/memif.h>
37
38 #define MEMIF_DEBUG 1
39
40 #if MEMIF_DEBUG == 1
41 #define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
42 #define DEBUG_UNIX_LOG(...) clib_unix_warning(__VA_ARGS__)
43 #else
44 #define DEBUG_LOG(...)
45 #endif
46
47 memif_main_t memif_main;
48
49 static clib_error_t *memif_conn_fd_read_ready (unix_file_t * uf);
50 static clib_error_t *memif_int_fd_read_ready (unix_file_t * uf);
51
52 static u32
53 memif_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, u32 flags)
54 {
55   /* nothing for now */
56   return 0;
57 }
58
59 static void
60 memif_remove_pending_conn (memif_pending_conn_t * pending_conn)
61 {
62   memif_main_t *mm = &memif_main;
63
64   unix_file_del (&unix_main,
65                  unix_main.file_pool + pending_conn->connection.index);
66   pool_put (mm->pending_conns, pending_conn);
67 }
68
69 static void
70 memif_connect (vlib_main_t * vm, memif_if_t * mif)
71 {
72   vnet_main_t *vnm = vnet_get_main ();
73   int num_rings = mif->num_s2m_rings + mif->num_m2s_rings;
74   memif_ring_data_t *rd = NULL;
75   vnet_hw_interface_t *hw;
76   u8 rid, rx_queues;
77   int ret;
78
79   vec_validate_aligned (mif->ring_data, num_rings - 1, CLIB_CACHE_LINE_BYTES);
80   vec_foreach (rd, mif->ring_data)
81   {
82     rd->last_head = 0;
83   }
84
85   mif->flags &= ~MEMIF_IF_FLAG_CONNECTING;
86   mif->flags |= MEMIF_IF_FLAG_CONNECTED;
87   vnet_hw_interface_set_flags (vnm, mif->hw_if_index,
88                                VNET_HW_INTERFACE_FLAG_LINK_UP);
89
90   hw = vnet_get_hw_interface (vnm, mif->hw_if_index);
91   hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE;
92   vnet_hw_interface_set_input_node (vnm, mif->hw_if_index,
93                                     memif_input_node.index);
94   rx_queues = memif_get_rx_queues (mif);
95   for (rid = 0; rid < rx_queues; rid++)
96     {
97       vnet_hw_interface_assign_rx_thread (vnm, mif->hw_if_index, rid, ~0);
98       ret = vnet_hw_interface_set_rx_mode (vnm, mif->hw_if_index, rid,
99                                            VNET_HW_INTERFACE_RX_MODE_INTERRUPT);
100       if (ret)
101         DEBUG_LOG ("Warning: unable to set rx mode for interface %d "
102                    "queue %d: rc=%d", mif->hw_if_index, rid, ret);
103     }
104 }
105
106 static void
107 memif_disconnect_do (vlib_main_t * vm, memif_if_t * mif)
108 {
109   vnet_main_t *vnm = vnet_get_main ();
110   u8 rid, rx_queues;
111   int rv;
112   memif_shm_t **shm;
113
114   mif->flags &= ~(MEMIF_IF_FLAG_CONNECTED | MEMIF_IF_FLAG_CONNECTING);
115   if (mif->hw_if_index != ~0)
116     vnet_hw_interface_set_flags (vnm, mif->hw_if_index, 0);
117
118   if (mif->connection.index != ~0)
119     {
120       unix_file_del (&unix_main, unix_main.file_pool + mif->connection.index);
121       mif->connection.index = ~0;
122       mif->connection.fd = -1;  /* closed in unix_file_del */
123     }
124
125   rx_queues = memif_get_rx_queues (mif);
126   for (rid = 0; rid < rx_queues; rid++)
127     {
128       rv = vnet_hw_interface_unassign_rx_thread (vnm, mif->hw_if_index, rid);
129       if (rv)
130         DEBUG_LOG ("Warning: unable to unassign interface %d, "
131                    "queue %d: rc=%d", mif->hw_if_index, rid, rv);
132     }
133
134   shm = (memif_shm_t **) mif->regions;
135   rv = munmap ((void *) *shm, mif->shared_mem_size);
136   if (rv)
137     DEBUG_UNIX_LOG ("Error: failed munmap call");
138
139   vec_free (mif->regions);
140 }
141
142 void
143 memif_disconnect (vlib_main_t * vm, memif_if_t * mif)
144 {
145   if (mif->interrupt_line.index != ~0)
146     {
147       unix_file_del (&unix_main,
148                      unix_main.file_pool + mif->interrupt_line.index);
149       mif->interrupt_line.index = ~0;
150       mif->interrupt_line.fd = -1;      /* closed in unix_file_del */
151     }
152
153   memif_disconnect_do (vm, mif);
154 }
155
156 static clib_error_t *
157 memif_process_connect_req (memif_pending_conn_t * pending_conn,
158                            memif_msg_t * req, struct ucred *slave_cr,
159                            int shm_fd, int int_fd)
160 {
161   memif_main_t *mm = &memif_main;
162   vlib_main_t *vm = vlib_get_main ();
163   int fd = pending_conn->connection.fd;
164   unix_file_t *uf = 0;
165   memif_if_t *mif = 0;
166   memif_msg_t resp = { 0 };
167   unix_file_t template = { 0 };
168   void *shm;
169   uword *p;
170   u8 retval = 0;
171   static clib_error_t *error = 0;
172
173   if (shm_fd == -1)
174     {
175       DEBUG_LOG
176         ("Connection request is missing shared memory file descriptor");
177       retval = 1;
178       goto response;
179     }
180
181   if (int_fd == -1)
182     {
183       DEBUG_LOG
184         ("Connection request is missing interrupt line file descriptor");
185       retval = 2;
186       goto response;
187     }
188
189   if (slave_cr == NULL)
190     {
191       DEBUG_LOG ("Connection request is missing slave credentials");
192       retval = 3;
193       goto response;
194     }
195
196   p = mhash_get (&mm->if_index_by_key, &req->key);
197   if (!p)
198     {
199       DEBUG_LOG
200         ("Connection request with unmatched key (0x%" PRIx64 ")", req->key);
201       retval = 4;
202       goto response;
203     }
204
205   mif = vec_elt_at_index (mm->interfaces, *p);
206   if (mif->listener_index != pending_conn->listener_index)
207     {
208       DEBUG_LOG
209         ("Connection request with non-matching listener (%d vs. %d)",
210          pending_conn->listener_index, mif->listener_index);
211       retval = 5;
212       goto response;
213     }
214
215   if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
216     {
217       DEBUG_LOG ("Memif slave does not accept connection requests");
218       retval = 6;
219       goto response;
220     }
221
222   if (mif->connection.fd != -1)
223     {
224       DEBUG_LOG
225         ("Memif with key 0x%" PRIx64 " is already connected", mif->key);
226       retval = 7;
227       goto response;
228     }
229
230   if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) == 0)
231     {
232       /* just silently decline the request */
233       retval = 8;
234       goto response;
235     }
236
237   if (req->shared_mem_size < sizeof (memif_shm_t))
238     {
239       DEBUG_LOG
240         ("Unexpectedly small shared memory segment received from slave.");
241       retval = 9;
242       goto response;
243     }
244
245   if ((shm =
246        mmap (NULL, req->shared_mem_size, PROT_READ | PROT_WRITE, MAP_SHARED,
247              shm_fd, 0)) == MAP_FAILED)
248     {
249       DEBUG_UNIX_LOG
250         ("Failed to map shared memory segment received from slave memif");
251       error = clib_error_return_unix (0, "mmap fd %d", shm_fd);
252       retval = 10;
253       goto response;
254     }
255
256   if (((memif_shm_t *) shm)->cookie != 0xdeadbeef)
257     {
258       DEBUG_LOG
259         ("Possibly corrupted shared memory segment received from slave memif");
260       munmap (shm, req->shared_mem_size);
261       retval = 11;
262       goto response;
263     }
264
265   mif->shared_mem_size = req->shared_mem_size;
266   mif->log2_ring_size = req->log2_ring_size;
267   mif->num_s2m_rings = req->num_s2m_rings;
268   mif->num_m2s_rings = req->num_m2s_rings;
269   mif->buffer_size = req->buffer_size;
270   mif->remote_pid = slave_cr->pid;
271   mif->remote_uid = slave_cr->uid;
272   vec_add1 (mif->regions, shm);
273
274   /* register interrupt line */
275   mif->interrupt_line.fd = int_fd;
276   template.read_function = memif_int_fd_read_ready;
277   template.file_descriptor = int_fd;
278   template.private_data = mif->if_index;
279   mif->interrupt_line.index = unix_file_add (&unix_main, &template);
280
281   /* change context for future messages */
282   uf = vec_elt_at_index (unix_main.file_pool, pending_conn->connection.index);
283   uf->private_data = mif->if_index << 1;
284   mif->connection = pending_conn->connection;
285   pool_put (mm->pending_conns, pending_conn);
286   pending_conn = 0;
287
288   memif_connect (vm, mif);
289
290 response:
291   resp.version = MEMIF_VERSION;
292   resp.type = MEMIF_MSG_TYPE_CONNECT_RESP;
293   resp.retval = retval;
294   if (send (fd, &resp, sizeof (resp), 0) < 0)
295     {
296       DEBUG_UNIX_LOG ("Failed to send connection response");
297       error = clib_error_return_unix (0, "send fd %d", fd);
298       if (pending_conn)
299         memif_remove_pending_conn (pending_conn);
300       else
301         memif_disconnect (vm, mif);
302     }
303   if (retval > 0)
304     {
305       if (shm_fd >= 0)
306         close (shm_fd);
307       if (int_fd >= 0)
308         close (int_fd);
309     }
310   return error;
311 }
312
313 static clib_error_t *
314 memif_process_connect_resp (memif_if_t * mif, memif_msg_t * resp)
315 {
316   vlib_main_t *vm = vlib_get_main ();
317
318   if ((mif->flags & MEMIF_IF_FLAG_IS_SLAVE) == 0)
319     {
320       DEBUG_LOG ("Memif master does not accept connection responses");
321       return 0;
322     }
323
324   if ((mif->flags & MEMIF_IF_FLAG_CONNECTING) == 0)
325     {
326       DEBUG_LOG ("Unexpected connection response");
327       return 0;
328     }
329
330   if (resp->retval == 0)
331     memif_connect (vm, mif);
332   else
333     memif_disconnect (vm, mif);
334
335   return 0;
336 }
337
338 static clib_error_t *
339 memif_conn_fd_read_ready (unix_file_t * uf)
340 {
341   memif_main_t *mm = &memif_main;
342   vlib_main_t *vm = vlib_get_main ();
343   memif_if_t *mif = 0;
344   memif_pending_conn_t *pending_conn = 0;
345   int fd_array[2] = { -1, -1 };
346   char ctl[CMSG_SPACE (sizeof (fd_array)) +
347            CMSG_SPACE (sizeof (struct ucred))] = { 0 };
348   struct msghdr mh = { 0 };
349   struct iovec iov[1];
350   struct ucred *cr = 0;
351   memif_msg_t msg = { 0 };
352   struct cmsghdr *cmsg;
353   ssize_t size;
354   static clib_error_t *error = 0;
355
356   iov[0].iov_base = (void *) &msg;
357   iov[0].iov_len = sizeof (memif_msg_t);
358   mh.msg_iov = iov;
359   mh.msg_iovlen = 1;
360   mh.msg_control = ctl;
361   mh.msg_controllen = sizeof (ctl);
362
363   /* grab the appropriate context */
364   if (uf->private_data & 1)
365     pending_conn = vec_elt_at_index (mm->pending_conns,
366                                      uf->private_data >> 1);
367   else
368     mif = vec_elt_at_index (mm->interfaces, uf->private_data >> 1);
369
370   /* Stop workers to avoid end of the world */
371   vlib_worker_thread_barrier_sync (vlib_get_main ());
372
373   /* receive the incoming message */
374   size = recvmsg (uf->file_descriptor, &mh, 0);
375   if (size != sizeof (memif_msg_t))
376     {
377       if (size == 0)
378         {
379           if (pending_conn)
380             memif_remove_pending_conn (pending_conn);
381           else
382             memif_disconnect_do (vm, mif);
383           goto return_ok;
384         }
385
386       DEBUG_UNIX_LOG ("Malformed message received on fd %d",
387                       uf->file_descriptor);
388       error = clib_error_return_unix (0, "recvmsg fd %d",
389                                       uf->file_descriptor);
390       goto disconnect;
391     }
392
393   /* check version of the sender's memif plugin */
394   if (msg.version != MEMIF_VERSION)
395     {
396       DEBUG_LOG ("Memif version mismatch");
397       goto disconnect;
398     }
399
400   /* process the message based on its type */
401   switch (msg.type)
402     {
403     case MEMIF_MSG_TYPE_CONNECT_REQ:
404       if (pending_conn == 0)
405         DEBUG_LOG ("Received unexpected connection request");
406       else
407         {
408           /* Read anciliary data */
409           cmsg = CMSG_FIRSTHDR (&mh);
410           while (cmsg)
411             {
412               if (cmsg->cmsg_level == SOL_SOCKET
413                   && cmsg->cmsg_type == SCM_CREDENTIALS)
414                 {
415                   cr = (struct ucred *) CMSG_DATA (cmsg);
416                 }
417               else if (cmsg->cmsg_level == SOL_SOCKET
418                        && cmsg->cmsg_type == SCM_RIGHTS)
419                 {
420                   memcpy (fd_array, CMSG_DATA (cmsg), sizeof (fd_array));
421                 }
422               cmsg = CMSG_NXTHDR (&mh, cmsg);
423             }
424           error = memif_process_connect_req (pending_conn, &msg, cr,
425                                              fd_array[0], fd_array[1]);
426         }
427       break;
428
429     case MEMIF_MSG_TYPE_CONNECT_RESP:
430       if (mif == 0)
431         DEBUG_LOG ("Received unexpected connection response");
432       else
433         error = memif_process_connect_resp (mif, &msg);
434       break;
435
436     case MEMIF_MSG_TYPE_DISCONNECT:
437       goto disconnect;
438
439     default:
440       DEBUG_LOG ("Received unknown message type");
441       goto disconnect;
442     }
443
444 return_ok:
445   vlib_worker_thread_barrier_release (vlib_get_main ());
446   return error;
447
448 disconnect:
449   if (pending_conn)
450     memif_remove_pending_conn (pending_conn);
451   else
452     memif_disconnect (vm, mif);
453   vlib_worker_thread_barrier_release (vlib_get_main ());
454   return error;
455 }
456
457 static clib_error_t *
458 memif_int_fd_read_ready (unix_file_t * uf)
459 {
460   memif_main_t *mm = &memif_main;
461   vnet_main_t *vnm = vnet_get_main ();
462   memif_if_t *mif = vec_elt_at_index (mm->interfaces, uf->private_data);
463   u8 b;
464   ssize_t size;
465
466   size = read (uf->file_descriptor, &b, sizeof (b));
467   if (0 == size)
468     {
469       /* interrupt line was disconnected */
470       unix_file_del (&unix_main,
471                      unix_main.file_pool + mif->interrupt_line.index);
472       mif->interrupt_line.index = ~0;
473       mif->interrupt_line.fd = -1;
474     }
475   else
476     vnet_device_input_set_interrupt_pending (vnm, mif->hw_if_index, b);
477
478   return 0;
479 }
480
481 static clib_error_t *
482 memif_conn_fd_accept_ready (unix_file_t * uf)
483 {
484   memif_main_t *mm = &memif_main;
485   memif_listener_t *listener = 0;
486   memif_pending_conn_t *pending_conn = 0;
487   int addr_len;
488   struct sockaddr_un client;
489   int conn_fd;
490   unix_file_t template = { 0 };
491
492   listener = pool_elt_at_index (mm->listeners, uf->private_data);
493
494   addr_len = sizeof (client);
495   conn_fd = accept (uf->file_descriptor,
496                     (struct sockaddr *) &client, (socklen_t *) & addr_len);
497
498   if (conn_fd < 0)
499     return clib_error_return_unix (0, "accept fd %d", uf->file_descriptor);
500
501   pool_get (mm->pending_conns, pending_conn);
502   pending_conn->index = pending_conn - mm->pending_conns;
503   pending_conn->listener_index = listener->index;
504   pending_conn->connection.fd = conn_fd;
505
506   template.read_function = memif_conn_fd_read_ready;
507   template.file_descriptor = conn_fd;
508   template.private_data = (pending_conn->index << 1) | 1;
509   pending_conn->connection.index = unix_file_add (&unix_main, &template);
510
511   return 0;
512 }
513
514 static void
515 memif_connect_master (vlib_main_t * vm, memif_if_t * mif)
516 {
517   memif_msg_t msg;
518   struct msghdr mh = { 0 };
519   struct iovec iov[1];
520   struct cmsghdr *cmsg;
521   int mfd = -1;
522   int rv;
523   int fd_array[2] = { -1, -1 };
524   char ctl[CMSG_SPACE (sizeof (fd_array))];
525   memif_ring_t *ring = NULL;
526   int i, j;
527   void *shm = 0;
528   u64 buffer_offset;
529   unix_file_t template = { 0 };
530
531   msg.version = MEMIF_VERSION;
532   msg.type = MEMIF_MSG_TYPE_CONNECT_REQ;
533   msg.key = mif->key;
534   msg.log2_ring_size = mif->log2_ring_size;
535   msg.num_s2m_rings = mif->num_s2m_rings;
536   msg.num_m2s_rings = mif->num_m2s_rings;
537   msg.buffer_size = mif->buffer_size;
538
539   buffer_offset = sizeof (memif_shm_t) +
540     (mif->num_s2m_rings + mif->num_m2s_rings) *
541     (sizeof (memif_ring_t) +
542      sizeof (memif_desc_t) * (1 << mif->log2_ring_size));
543
544   msg.shared_mem_size = buffer_offset +
545     mif->buffer_size * (1 << mif->log2_ring_size) * (mif->num_s2m_rings +
546                                                      mif->num_m2s_rings);
547
548   if ((mfd = memfd_create ("shared mem", MFD_ALLOW_SEALING)) == -1)
549     {
550       DEBUG_LOG ("Failed to create anonymous file");
551       goto error;
552     }
553
554   if ((fcntl (mfd, F_ADD_SEALS, F_SEAL_SHRINK)) == -1)
555     {
556       DEBUG_UNIX_LOG ("Failed to seal an anonymous file off from truncating");
557       goto error;
558     }
559
560   if ((ftruncate (mfd, msg.shared_mem_size)) == -1)
561     {
562       DEBUG_UNIX_LOG ("Failed to extend the size of an anonymous file");
563       goto error;
564     }
565
566   if ((shm = mmap (NULL, msg.shared_mem_size, PROT_READ | PROT_WRITE,
567                    MAP_SHARED, mfd, 0)) == MAP_FAILED)
568     {
569       DEBUG_UNIX_LOG ("Failed to map anonymous file into memory");
570       goto error;
571     }
572
573   mif->shared_mem_size = msg.shared_mem_size;
574   vec_add1 (mif->regions, shm);
575   ((memif_shm_t *) mif->regions[0])->cookie = 0xdeadbeef;
576
577   for (i = 0; i < mif->num_s2m_rings; i++)
578     {
579       ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
580       ring->head = ring->tail = 0;
581       for (j = 0; j < (1 << mif->log2_ring_size); j++)
582         {
583           u16 slot = i * (1 << mif->log2_ring_size) + j;
584           ring->desc[j].region = 0;
585           ring->desc[j].offset =
586             buffer_offset + (u32) (slot * mif->buffer_size);
587           ring->desc[j].buffer_length = mif->buffer_size;
588         }
589     }
590   for (i = 0; i < mif->num_m2s_rings; i++)
591     {
592       ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
593       ring->head = ring->tail = 0;
594       for (j = 0; j < (1 << mif->log2_ring_size); j++)
595         {
596           u16 slot =
597             (i + mif->num_s2m_rings) * (1 << mif->log2_ring_size) + j;
598           ring->desc[j].region = 0;
599           ring->desc[j].offset =
600             buffer_offset + (u32) (slot * mif->buffer_size);
601           ring->desc[j].buffer_length = mif->buffer_size;
602         }
603     }
604
605   iov[0].iov_base = (void *) &msg;
606   iov[0].iov_len = sizeof (memif_msg_t);
607   mh.msg_iov = iov;
608   mh.msg_iovlen = 1;
609
610   /* create interrupt socket */
611   if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd_array) < 0)
612     {
613       DEBUG_UNIX_LOG ("Failed to create a pair of connected sockets");
614       goto error;
615     }
616
617   mif->interrupt_line.fd = fd_array[0];
618   template.read_function = memif_int_fd_read_ready;
619   template.file_descriptor = mif->interrupt_line.fd;
620   template.private_data = mif->if_index;
621   mif->interrupt_line.index = unix_file_add (&unix_main, &template);
622
623   memset (&ctl, 0, sizeof (ctl));
624   mh.msg_control = ctl;
625   mh.msg_controllen = sizeof (ctl);
626   cmsg = CMSG_FIRSTHDR (&mh);
627   cmsg->cmsg_len = CMSG_LEN (sizeof (fd_array));
628   cmsg->cmsg_level = SOL_SOCKET;
629   cmsg->cmsg_type = SCM_RIGHTS;
630   fd_array[0] = mfd;
631   memcpy (CMSG_DATA (cmsg), fd_array, sizeof (fd_array));
632
633   mif->flags |= MEMIF_IF_FLAG_CONNECTING;
634   rv = sendmsg (mif->connection.fd, &mh, 0);
635   if (rv < 0)
636     {
637       DEBUG_UNIX_LOG ("Failed to send memif connection request");
638       goto error;
639     }
640
641   /* No need to keep the descriptor open,
642    * mmap creates an extra reference to the underlying file */
643   close (mfd);
644   mfd = -1;
645   /* This FD is given to peer, so we can close it */
646   close (fd_array[1]);
647   fd_array[1] = -1;
648   return;
649
650 error:
651   if (mfd > -1)
652     close (mfd);
653   if (fd_array[1] > -1)
654     close (fd_array[1]);
655   memif_disconnect (vm, mif);
656 }
657
658 static uword
659 memif_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
660 {
661   memif_main_t *mm = &memif_main;
662   memif_if_t *mif;
663   struct sockaddr_un sun;
664   int sockfd;
665   uword *event_data = 0, event_type;
666   unix_file_t template = { 0 };
667   u8 enabled = 0;
668   f64 start_time, last_run_duration = 0, now;
669
670   sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
671   if (sockfd < 0)
672     {
673       DEBUG_UNIX_LOG ("socket AF_UNIX");
674       return 0;
675     }
676   sun.sun_family = AF_UNIX;
677   template.read_function = memif_conn_fd_read_ready;
678
679   while (1)
680     {
681       if (enabled)
682         vlib_process_wait_for_event_or_clock (vm,
683                                               (f64) 3 - last_run_duration);
684       else
685         vlib_process_wait_for_event (vm);
686
687       event_type = vlib_process_get_events (vm, &event_data);
688       vec_reset_length (event_data);
689
690       switch (event_type)
691         {
692         case ~0:
693           break;
694         case MEMIF_PROCESS_EVENT_START:
695           enabled = 1;
696           break;
697         case MEMIF_PROCESS_EVENT_STOP:
698           enabled = 0;
699           continue;
700         default:
701           ASSERT (0);
702         }
703
704       last_run_duration = start_time = vlib_time_now (vm);
705       /* *INDENT-OFF* */
706       pool_foreach (mif, mm->interfaces,
707         ({
708           /* Allow no more than 10us without a pause */
709           now = vlib_time_now (vm);
710           if (now > start_time + 10e-6)
711             {
712               vlib_process_suspend (vm, 100e-6);        /* suspend for 100 us */
713               start_time = vlib_time_now (vm);
714             }
715
716           if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) == 0)
717             continue;
718
719           if (mif->flags & MEMIF_IF_FLAG_CONNECTING)
720             continue;
721
722           if (mif->flags & MEMIF_IF_FLAG_CONNECTED)
723             continue;
724
725           if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
726             {
727               strncpy (sun.sun_path, (char *) mif->socket_filename,
728                        sizeof (sun.sun_path) - 1);
729
730               if (connect
731                   (sockfd, (struct sockaddr *) &sun,
732                    sizeof (struct sockaddr_un)) == 0)
733                 {
734                   mif->connection.fd = sockfd;
735                   template.file_descriptor = sockfd;
736                   template.private_data = mif->if_index << 1;
737                   mif->connection.index = unix_file_add (&unix_main, &template);
738                   memif_connect_master (vm, mif);
739
740                   /* grab another fd */
741                   sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
742                   if (sockfd < 0)
743                     {
744                       DEBUG_UNIX_LOG ("socket AF_UNIX");
745                       return 0;
746                     }
747                 }
748             }
749         }));
750       /* *INDENT-ON* */
751       last_run_duration = vlib_time_now (vm) - last_run_duration;
752     }
753   return 0;
754 }
755
756 /* *INDENT-OFF* */
757 VLIB_REGISTER_NODE (memif_process_node,static) = {
758   .function = memif_process,
759   .type = VLIB_NODE_TYPE_PROCESS,
760   .name = "memif-process",
761 };
762 /* *INDENT-ON* */
763
764 static void
765 memif_close_if (memif_main_t * mm, memif_if_t * mif)
766 {
767   vlib_main_t *vm = vlib_get_main ();
768   memif_listener_t *listener = 0;
769   memif_pending_conn_t *pending_conn = 0;
770
771   memif_disconnect (vm, mif);
772
773   if (mif->listener_index != (uword) ~ 0)
774     {
775       listener = pool_elt_at_index (mm->listeners, mif->listener_index);
776       if (--listener->usage_counter == 0)
777         {
778           /* not used anymore -> remove the socket and pending connections */
779
780           /* *INDENT-OFF* */
781           pool_foreach (pending_conn, mm->pending_conns,
782             ({
783                if (pending_conn->listener_index == mif->listener_index)
784                  {
785                    memif_remove_pending_conn (pending_conn);
786                  }
787              }));
788           /* *INDENT-ON* */
789
790           unix_file_del (&unix_main,
791                          unix_main.file_pool + listener->socket.index);
792           pool_put (mm->listeners, listener);
793           unlink ((char *) mif->socket_filename);
794         }
795     }
796
797   clib_spinlock_free (&mif->lockp);
798
799   mhash_unset (&mm->if_index_by_key, &mif->key, &mif->if_index);
800   vec_free (mif->socket_filename);
801   vec_free (mif->ring_data);
802
803   memset (mif, 0, sizeof (*mif));
804   pool_put (mm->interfaces, mif);
805 }
806
807 int
808 memif_worker_thread_enable ()
809 {
810   /* if worker threads are enabled, switch to polling mode */
811   /* *INDENT-OFF* */
812   foreach_vlib_main ((
813                        {
814                        vlib_node_set_state (this_vlib_main,
815                                             memif_input_node.index,
816                                             VLIB_NODE_STATE_POLLING);
817                        }));
818   /* *INDENT-ON* */
819   return 0;
820 }
821
822 int
823 memif_worker_thread_disable ()
824 {
825   /* *INDENT-OFF* */
826   foreach_vlib_main ((
827                        {
828                        vlib_node_set_state (this_vlib_main,
829                                             memif_input_node.index,
830                                             VLIB_NODE_STATE_INTERRUPT);
831                        }));
832   /* *INDENT-ON* */
833   return 0;
834 }
835
836 int
837 memif_create_if (vlib_main_t * vm, memif_create_if_args_t * args)
838 {
839   memif_main_t *mm = &memif_main;
840   vlib_thread_main_t *tm = vlib_get_thread_main ();
841   vnet_main_t *vnm = vnet_get_main ();
842   memif_if_t *mif = 0;
843   vnet_sw_interface_t *sw;
844   clib_error_t *error = 0;
845   int ret = 0;
846   uword *p;
847
848   p = mhash_get (&mm->if_index_by_key, &args->key);
849   if (p)
850     return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
851
852   pool_get (mm->interfaces, mif);
853   memset (mif, 0, sizeof (*mif));
854   mif->key = args->key;
855   mif->if_index = mif - mm->interfaces;
856   mif->sw_if_index = mif->hw_if_index = mif->per_interface_next_index = ~0;
857   mif->listener_index = ~0;
858   mif->connection.index = mif->interrupt_line.index = ~0;
859   mif->connection.fd = mif->interrupt_line.fd = -1;
860
861   if (tm->n_vlib_mains > 1)
862     clib_spinlock_init (&mif->lockp);
863
864   if (!args->hw_addr_set)
865     {
866       f64 now = vlib_time_now (vm);
867       u32 rnd;
868       rnd = (u32) (now * 1e6);
869       rnd = random_u32 (&rnd);
870
871       memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
872       args->hw_addr[0] = 2;
873       args->hw_addr[1] = 0xfe;
874     }
875
876   error = ethernet_register_interface (vnm, memif_device_class.index,
877                                        mif->if_index, args->hw_addr,
878                                        &mif->hw_if_index,
879                                        memif_eth_flag_change);
880
881   if (error)
882     {
883       clib_error_report (error);
884       ret = VNET_API_ERROR_SYSCALL_ERROR_1;
885       goto error;
886     }
887
888   sw = vnet_get_hw_sw_interface (vnm, mif->hw_if_index);
889   mif->sw_if_index = sw->sw_if_index;
890
891   mif->log2_ring_size = args->log2_ring_size;
892   mif->buffer_size = args->buffer_size;
893
894   mif->num_s2m_rings = args->rx_queues;
895   mif->num_m2s_rings = args->tx_queues;
896
897   mhash_set_mem (&mm->if_index_by_key, &args->key, &mif->if_index, 0);
898
899   if (args->socket_filename != 0)
900     mif->socket_filename = args->socket_filename;
901   else
902     mif->socket_filename = vec_dup (mm->default_socket_filename);
903
904   args->sw_if_index = mif->sw_if_index;
905
906   if (args->is_master)
907     {
908       struct sockaddr_un un = { 0 };
909       struct stat file_stat;
910       int on = 1;
911       memif_listener_t *listener = 0;
912
913       if (stat ((char *) mif->socket_filename, &file_stat) == 0)
914         {
915           if (!S_ISSOCK (file_stat.st_mode))
916             {
917               errno = ENOTSOCK;
918               ret = VNET_API_ERROR_SYSCALL_ERROR_2;
919               goto error;
920             }
921           /* *INDENT-OFF* */
922           pool_foreach (listener, mm->listeners,
923             ({
924                if (listener->sock_dev == file_stat.st_dev &&
925                    listener->sock_ino == file_stat.st_ino)
926                  {
927                    /* attach memif to the existing listener */
928                    mif->listener_index = listener->index;
929                    ++listener->usage_counter;
930                    goto signal;
931                  }
932              }));
933           /* *INDENT-ON* */
934           unlink ((char *) mif->socket_filename);
935         }
936
937       pool_get (mm->listeners, listener);
938       memset (listener, 0, sizeof (*listener));
939       listener->socket.fd = -1;
940       listener->socket.index = ~0;
941       listener->index = listener - mm->listeners;
942       listener->usage_counter = 1;
943
944       if ((listener->socket.fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
945         {
946           ret = VNET_API_ERROR_SYSCALL_ERROR_3;
947           goto error;
948         }
949
950       un.sun_family = AF_UNIX;
951       strncpy ((char *) un.sun_path, (char *) mif->socket_filename,
952                sizeof (un.sun_path) - 1);
953
954       if (setsockopt (listener->socket.fd, SOL_SOCKET, SO_PASSCRED,
955                       &on, sizeof (on)) < 0)
956         {
957           ret = VNET_API_ERROR_SYSCALL_ERROR_4;
958           goto error;
959         }
960       if (bind (listener->socket.fd, (struct sockaddr *) &un,
961                 sizeof (un)) == -1)
962         {
963           ret = VNET_API_ERROR_SYSCALL_ERROR_5;
964           goto error;
965         }
966       if (listen (listener->socket.fd, 1) == -1)
967         {
968           ret = VNET_API_ERROR_SYSCALL_ERROR_6;
969           goto error;
970         }
971
972       if (stat ((char *) mif->socket_filename, &file_stat) == -1)
973         {
974           ret = VNET_API_ERROR_SYSCALL_ERROR_7;
975           goto error;
976         }
977
978       listener->sock_dev = file_stat.st_dev;
979       listener->sock_ino = file_stat.st_ino;
980
981       unix_file_t template = { 0 };
982       template.read_function = memif_conn_fd_accept_ready;
983       template.file_descriptor = listener->socket.fd;
984       template.private_data = listener->index;
985       listener->socket.index = unix_file_add (&unix_main, &template);
986
987       mif->listener_index = listener->index;
988     }
989   else
990     {
991       mif->flags |= MEMIF_IF_FLAG_IS_SLAVE;
992     }
993
994 #if 0
995   /* use configured or generate random MAC address */
996   if (!args->hw_addr_set &&
997       tm->n_vlib_mains > 1 && pool_elts (mm->interfaces) == 1)
998     memif_worker_thread_enable ();
999 #endif
1000
1001 signal:
1002   if (pool_elts (mm->interfaces) == 1)
1003     {
1004       vlib_process_signal_event (vm, memif_process_node.index,
1005                                  MEMIF_PROCESS_EVENT_START, 0);
1006     }
1007   return 0;
1008
1009 error:
1010   if (mif->hw_if_index != ~0)
1011     {
1012       ethernet_delete_interface (vnm, mif->hw_if_index);
1013       mif->hw_if_index = ~0;
1014     }
1015   memif_close_if (mm, mif);
1016   return ret;
1017 }
1018
1019 int
1020 memif_delete_if (vlib_main_t * vm, u64 key)
1021 {
1022   vnet_main_t *vnm = vnet_get_main ();
1023   memif_main_t *mm = &memif_main;
1024   memif_if_t *mif;
1025   uword *p;
1026   u32 hw_if_index;
1027
1028   p = mhash_get (&mm->if_index_by_key, &key);
1029   if (p == NULL)
1030     {
1031       DEBUG_LOG ("Memory interface with key 0x%" PRIx64 " does not exist",
1032                  key);
1033       return VNET_API_ERROR_SYSCALL_ERROR_1;
1034     }
1035   mif = pool_elt_at_index (mm->interfaces, p[0]);
1036   mif->flags |= MEMIF_IF_FLAG_DELETING;
1037
1038   /* bring down the interface */
1039   vnet_sw_interface_set_flags (vnm, mif->sw_if_index, 0);
1040
1041   hw_if_index = mif->hw_if_index;
1042   memif_close_if (mm, mif);
1043
1044   /* remove the interface */
1045   ethernet_delete_interface (vnm, hw_if_index);
1046   if (pool_elts (mm->interfaces) == 0)
1047     {
1048       vlib_process_signal_event (vm, memif_process_node.index,
1049                                  MEMIF_PROCESS_EVENT_STOP, 0);
1050     }
1051
1052 #if 0
1053   if (tm->n_vlib_mains > 1 && pool_elts (mm->interfaces) == 0)
1054     memif_worker_thread_disable ();
1055 #endif
1056
1057   return 0;
1058 }
1059
1060 static clib_error_t *
1061 memif_init (vlib_main_t * vm)
1062 {
1063   memif_main_t *mm = &memif_main;
1064   vlib_thread_main_t *tm = vlib_get_thread_main ();
1065   vlib_thread_registration_t *tr;
1066   uword *p;
1067
1068   memset (mm, 0, sizeof (memif_main_t));
1069
1070   mm->input_cpu_first_index = 0;
1071   mm->input_cpu_count = 1;
1072
1073   /* initialize binary API */
1074   memif_plugin_api_hookup (vm);
1075
1076   /* find out which cpus will be used for input */
1077   p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1078   tr = p ? (vlib_thread_registration_t *) p[0] : 0;
1079
1080   if (tr && tr->count > 0)
1081     {
1082       mm->input_cpu_first_index = tr->first_index;
1083       mm->input_cpu_count = tr->count;
1084     }
1085
1086   mhash_init (&mm->if_index_by_key, sizeof (uword), sizeof (u64));
1087
1088   vec_validate_aligned (mm->rx_buffers, tm->n_vlib_mains - 1,
1089                         CLIB_CACHE_LINE_BYTES);
1090
1091   /* set default socket filename */
1092   vec_validate (mm->default_socket_filename,
1093                 strlen (MEMIF_DEFAULT_SOCKET_FILENAME));
1094   strncpy ((char *) mm->default_socket_filename,
1095            MEMIF_DEFAULT_SOCKET_FILENAME,
1096            vec_len (mm->default_socket_filename) - 1);
1097
1098   return 0;
1099 }
1100
1101 VLIB_INIT_FUNCTION (memif_init);
1102
1103 /* *INDENT-OFF* */
1104 VLIB_PLUGIN_REGISTER () = {
1105     .version = VPP_BUILD_VER,
1106     .description = "Packet Memory Interface (experimetal)",
1107 };
1108 /* *INDENT-ON* */
1109
1110 /*
1111  * fd.io coding-style-patch-verification: ON
1112  *
1113  * Local Variables:
1114  * eval: (c-set-style "gnu")
1115  * End:
1116  */