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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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 *------------------------------------------------------------------
21 #include <sys/types.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
28 #include <sys/prctl.h>
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>
41 #define DEBUG_LOG(...) clib_warning(__VA_ARGS__)
42 #define DEBUG_UNIX_LOG(...) clib_unix_warning(__VA_ARGS__)
44 #define DEBUG_LOG(...)
47 memif_main_t memif_main;
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);
53 memif_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi, u32 flags)
60 memif_remove_pending_conn (memif_pending_conn_t * pending_conn)
62 memif_main_t *mm = &memif_main;
64 unix_file_del (&unix_main,
65 unix_main.file_pool + pending_conn->connection.index);
66 pool_put (mm->pending_conns, pending_conn);
70 memif_connect (vlib_main_t * vm, memif_if_t * mif)
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;
79 vec_validate_aligned (mif->ring_data, num_rings - 1, CLIB_CACHE_LINE_BYTES);
80 vec_foreach (rd, mif->ring_data)
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);
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++)
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);
101 DEBUG_LOG ("Warning: unable to set rx mode for interface %d "
102 "queue %d: rc=%d", mif->hw_if_index, rid, ret);
107 memif_disconnect_do (vlib_main_t * vm, memif_if_t * mif)
109 vnet_main_t *vnm = vnet_get_main ();
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);
118 if (mif->connection.index != ~0)
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 */
125 rx_queues = memif_get_rx_queues (mif);
126 for (rid = 0; rid < rx_queues; rid++)
128 rv = vnet_hw_interface_unassign_rx_thread (vnm, mif->hw_if_index, rid);
130 DEBUG_LOG ("Warning: unable to unassign interface %d, "
131 "queue %d: rc=%d", mif->hw_if_index, rid, rv);
134 shm = (memif_shm_t **) mif->regions;
135 rv = munmap ((void *) *shm, mif->shared_mem_size);
137 DEBUG_UNIX_LOG ("Error: failed munmap call");
139 vec_free (mif->regions);
143 memif_disconnect (vlib_main_t * vm, memif_if_t * mif)
145 if (mif->interrupt_line.index != ~0)
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 */
153 memif_disconnect_do (vm, mif);
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)
161 memif_main_t *mm = &memif_main;
162 vlib_main_t *vm = vlib_get_main ();
163 int fd = pending_conn->connection.fd;
166 memif_msg_t resp = { 0 };
167 unix_file_t template = { 0 };
171 static clib_error_t *error = 0;
176 ("Connection request is missing shared memory file descriptor");
184 ("Connection request is missing interrupt line file descriptor");
189 if (slave_cr == NULL)
191 DEBUG_LOG ("Connection request is missing slave credentials");
196 p = mhash_get (&mm->if_index_by_key, &req->key);
200 ("Connection request with unmatched key (0x%" PRIx64 ")", req->key);
205 mif = vec_elt_at_index (mm->interfaces, *p);
206 if (mif->listener_index != pending_conn->listener_index)
209 ("Connection request with non-matching listener (%d vs. %d)",
210 pending_conn->listener_index, mif->listener_index);
215 if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
217 DEBUG_LOG ("Memif slave does not accept connection requests");
222 if (mif->connection.fd != -1)
225 ("Memif with key 0x%" PRIx64 " is already connected", mif->key);
230 if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) == 0)
232 /* just silently decline the request */
237 if (req->shared_mem_size < sizeof (memif_shm_t))
240 ("Unexpectedly small shared memory segment received from slave.");
246 mmap (NULL, req->shared_mem_size, PROT_READ | PROT_WRITE, MAP_SHARED,
247 shm_fd, 0)) == MAP_FAILED)
250 ("Failed to map shared memory segment received from slave memif");
251 error = clib_error_return_unix (0, "mmap fd %d", shm_fd);
256 if (((memif_shm_t *) shm)->cookie != 0xdeadbeef)
259 ("Possibly corrupted shared memory segment received from slave memif");
260 munmap (shm, req->shared_mem_size);
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);
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);
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);
288 memif_connect (vm, mif);
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)
296 DEBUG_UNIX_LOG ("Failed to send connection response");
297 error = clib_error_return_unix (0, "send fd %d", fd);
299 memif_remove_pending_conn (pending_conn);
301 memif_disconnect (vm, mif);
313 static clib_error_t *
314 memif_process_connect_resp (memif_if_t * mif, memif_msg_t * resp)
316 vlib_main_t *vm = vlib_get_main ();
318 if ((mif->flags & MEMIF_IF_FLAG_IS_SLAVE) == 0)
320 DEBUG_LOG ("Memif master does not accept connection responses");
324 if ((mif->flags & MEMIF_IF_FLAG_CONNECTING) == 0)
326 DEBUG_LOG ("Unexpected connection response");
330 if (resp->retval == 0)
331 memif_connect (vm, mif);
333 memif_disconnect (vm, mif);
338 static clib_error_t *
339 memif_conn_fd_read_ready (unix_file_t * uf)
341 memif_main_t *mm = &memif_main;
342 vlib_main_t *vm = vlib_get_main ();
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 };
350 struct ucred *cr = 0;
351 memif_msg_t msg = { 0 };
352 struct cmsghdr *cmsg;
354 static clib_error_t *error = 0;
356 iov[0].iov_base = (void *) &msg;
357 iov[0].iov_len = sizeof (memif_msg_t);
360 mh.msg_control = ctl;
361 mh.msg_controllen = sizeof (ctl);
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);
368 mif = vec_elt_at_index (mm->interfaces, uf->private_data >> 1);
370 /* Stop workers to avoid end of the world */
371 vlib_worker_thread_barrier_sync (vlib_get_main ());
373 /* receive the incoming message */
374 size = recvmsg (uf->file_descriptor, &mh, 0);
375 if (size != sizeof (memif_msg_t))
380 memif_remove_pending_conn (pending_conn);
382 memif_disconnect_do (vm, mif);
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);
393 /* check version of the sender's memif plugin */
394 if (msg.version != MEMIF_VERSION)
396 DEBUG_LOG ("Memif version mismatch");
400 /* process the message based on its type */
403 case MEMIF_MSG_TYPE_CONNECT_REQ:
404 if (pending_conn == 0)
405 DEBUG_LOG ("Received unexpected connection request");
408 /* Read anciliary data */
409 cmsg = CMSG_FIRSTHDR (&mh);
412 if (cmsg->cmsg_level == SOL_SOCKET
413 && cmsg->cmsg_type == SCM_CREDENTIALS)
415 cr = (struct ucred *) CMSG_DATA (cmsg);
417 else if (cmsg->cmsg_level == SOL_SOCKET
418 && cmsg->cmsg_type == SCM_RIGHTS)
420 memcpy (fd_array, CMSG_DATA (cmsg), sizeof (fd_array));
422 cmsg = CMSG_NXTHDR (&mh, cmsg);
424 error = memif_process_connect_req (pending_conn, &msg, cr,
425 fd_array[0], fd_array[1]);
429 case MEMIF_MSG_TYPE_CONNECT_RESP:
431 DEBUG_LOG ("Received unexpected connection response");
433 error = memif_process_connect_resp (mif, &msg);
436 case MEMIF_MSG_TYPE_DISCONNECT:
440 DEBUG_LOG ("Received unknown message type");
445 vlib_worker_thread_barrier_release (vlib_get_main ());
450 memif_remove_pending_conn (pending_conn);
452 memif_disconnect (vm, mif);
453 vlib_worker_thread_barrier_release (vlib_get_main ());
457 static clib_error_t *
458 memif_int_fd_read_ready (unix_file_t * uf)
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);
466 size = read (uf->file_descriptor, &b, sizeof (b));
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;
476 DEBUG_UNIX_LOG ("Failed to read from socket");
478 vnet_device_input_set_interrupt_pending (vnm, mif->hw_if_index, b);
483 static clib_error_t *
484 memif_conn_fd_accept_ready (unix_file_t * uf)
486 memif_main_t *mm = &memif_main;
487 memif_listener_t *listener = 0;
488 memif_pending_conn_t *pending_conn = 0;
490 struct sockaddr_un client;
492 unix_file_t template = { 0 };
494 listener = pool_elt_at_index (mm->listeners, uf->private_data);
496 addr_len = sizeof (client);
497 conn_fd = accept (uf->file_descriptor,
498 (struct sockaddr *) &client, (socklen_t *) & addr_len);
501 return clib_error_return_unix (0, "accept fd %d", uf->file_descriptor);
503 pool_get (mm->pending_conns, pending_conn);
504 pending_conn->index = pending_conn - mm->pending_conns;
505 pending_conn->listener_index = listener->index;
506 pending_conn->connection.fd = conn_fd;
508 template.read_function = memif_conn_fd_read_ready;
509 template.file_descriptor = conn_fd;
510 template.private_data = (pending_conn->index << 1) | 1;
511 pending_conn->connection.index = unix_file_add (&unix_main, &template);
517 memif_connect_master (vlib_main_t * vm, memif_if_t * mif)
520 struct msghdr mh = { 0 };
522 struct cmsghdr *cmsg;
525 int fd_array[2] = { -1, -1 };
526 char ctl[CMSG_SPACE (sizeof (fd_array))];
527 memif_ring_t *ring = NULL;
531 unix_file_t template = { 0 };
533 msg.version = MEMIF_VERSION;
534 msg.type = MEMIF_MSG_TYPE_CONNECT_REQ;
536 msg.log2_ring_size = mif->log2_ring_size;
537 msg.num_s2m_rings = mif->num_s2m_rings;
538 msg.num_m2s_rings = mif->num_m2s_rings;
539 msg.buffer_size = mif->buffer_size;
541 buffer_offset = sizeof (memif_shm_t) +
542 (mif->num_s2m_rings + mif->num_m2s_rings) *
543 (sizeof (memif_ring_t) +
544 sizeof (memif_desc_t) * (1 << mif->log2_ring_size));
546 msg.shared_mem_size = buffer_offset +
547 mif->buffer_size * (1 << mif->log2_ring_size) * (mif->num_s2m_rings +
550 if ((mfd = memfd_create ("shared mem", MFD_ALLOW_SEALING)) == -1)
552 DEBUG_LOG ("Failed to create anonymous file");
556 if ((fcntl (mfd, F_ADD_SEALS, F_SEAL_SHRINK)) == -1)
558 DEBUG_UNIX_LOG ("Failed to seal an anonymous file off from truncating");
562 if ((ftruncate (mfd, msg.shared_mem_size)) == -1)
564 DEBUG_UNIX_LOG ("Failed to extend the size of an anonymous file");
568 if ((shm = mmap (NULL, msg.shared_mem_size, PROT_READ | PROT_WRITE,
569 MAP_SHARED, mfd, 0)) == MAP_FAILED)
571 DEBUG_UNIX_LOG ("Failed to map anonymous file into memory");
575 mif->shared_mem_size = msg.shared_mem_size;
576 vec_add1 (mif->regions, shm);
577 ((memif_shm_t *) mif->regions[0])->cookie = 0xdeadbeef;
579 for (i = 0; i < mif->num_s2m_rings; i++)
581 ring = memif_get_ring (mif, MEMIF_RING_S2M, i);
582 ring->head = ring->tail = 0;
583 for (j = 0; j < (1 << mif->log2_ring_size); j++)
585 u16 slot = i * (1 << mif->log2_ring_size) + j;
586 ring->desc[j].region = 0;
587 ring->desc[j].offset =
588 buffer_offset + (u32) (slot * mif->buffer_size);
589 ring->desc[j].buffer_length = mif->buffer_size;
592 for (i = 0; i < mif->num_m2s_rings; i++)
594 ring = memif_get_ring (mif, MEMIF_RING_M2S, i);
595 ring->head = ring->tail = 0;
596 for (j = 0; j < (1 << mif->log2_ring_size); j++)
599 (i + mif->num_s2m_rings) * (1 << mif->log2_ring_size) + j;
600 ring->desc[j].region = 0;
601 ring->desc[j].offset =
602 buffer_offset + (u32) (slot * mif->buffer_size);
603 ring->desc[j].buffer_length = mif->buffer_size;
607 iov[0].iov_base = (void *) &msg;
608 iov[0].iov_len = sizeof (memif_msg_t);
612 /* create interrupt socket */
613 if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd_array) < 0)
615 DEBUG_UNIX_LOG ("Failed to create a pair of connected sockets");
619 mif->interrupt_line.fd = fd_array[0];
620 template.read_function = memif_int_fd_read_ready;
621 template.file_descriptor = mif->interrupt_line.fd;
622 template.private_data = mif->if_index;
623 mif->interrupt_line.index = unix_file_add (&unix_main, &template);
625 memset (&ctl, 0, sizeof (ctl));
626 mh.msg_control = ctl;
627 mh.msg_controllen = sizeof (ctl);
628 cmsg = CMSG_FIRSTHDR (&mh);
629 cmsg->cmsg_len = CMSG_LEN (sizeof (fd_array));
630 cmsg->cmsg_level = SOL_SOCKET;
631 cmsg->cmsg_type = SCM_RIGHTS;
633 memcpy (CMSG_DATA (cmsg), fd_array, sizeof (fd_array));
635 mif->flags |= MEMIF_IF_FLAG_CONNECTING;
636 rv = sendmsg (mif->connection.fd, &mh, 0);
639 DEBUG_UNIX_LOG ("Failed to send memif connection request");
643 /* No need to keep the descriptor open,
644 * mmap creates an extra reference to the underlying file */
647 /* This FD is given to peer, so we can close it */
655 if (fd_array[1] > -1)
657 memif_disconnect (vm, mif);
661 memif_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
663 memif_main_t *mm = &memif_main;
665 struct sockaddr_un sun;
667 uword *event_data = 0, event_type;
668 unix_file_t template = { 0 };
670 f64 start_time, last_run_duration = 0, now;
672 sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
675 DEBUG_UNIX_LOG ("socket AF_UNIX");
678 sun.sun_family = AF_UNIX;
679 template.read_function = memif_conn_fd_read_ready;
684 vlib_process_wait_for_event_or_clock (vm,
685 (f64) 3 - last_run_duration);
687 vlib_process_wait_for_event (vm);
689 event_type = vlib_process_get_events (vm, &event_data);
690 vec_reset_length (event_data);
696 case MEMIF_PROCESS_EVENT_START:
699 case MEMIF_PROCESS_EVENT_STOP:
706 last_run_duration = start_time = vlib_time_now (vm);
708 pool_foreach (mif, mm->interfaces,
710 /* Allow no more than 10us without a pause */
711 now = vlib_time_now (vm);
712 if (now > start_time + 10e-6)
714 vlib_process_suspend (vm, 100e-6); /* suspend for 100 us */
715 start_time = vlib_time_now (vm);
718 if ((mif->flags & MEMIF_IF_FLAG_ADMIN_UP) == 0)
721 if (mif->flags & MEMIF_IF_FLAG_CONNECTING)
724 if (mif->flags & MEMIF_IF_FLAG_CONNECTED)
727 if (mif->flags & MEMIF_IF_FLAG_IS_SLAVE)
729 strncpy (sun.sun_path, (char *) mif->socket_filename,
730 sizeof (sun.sun_path) - 1);
733 (sockfd, (struct sockaddr *) &sun,
734 sizeof (struct sockaddr_un)) == 0)
736 mif->connection.fd = sockfd;
737 template.file_descriptor = sockfd;
738 template.private_data = mif->if_index << 1;
739 mif->connection.index = unix_file_add (&unix_main, &template);
740 memif_connect_master (vm, mif);
742 /* grab another fd */
743 sockfd = socket (AF_UNIX, SOCK_STREAM, 0);
746 DEBUG_UNIX_LOG ("socket AF_UNIX");
753 last_run_duration = vlib_time_now (vm) - last_run_duration;
759 VLIB_REGISTER_NODE (memif_process_node,static) = {
760 .function = memif_process,
761 .type = VLIB_NODE_TYPE_PROCESS,
762 .name = "memif-process",
767 memif_close_if (memif_main_t * mm, memif_if_t * mif)
769 vlib_main_t *vm = vlib_get_main ();
770 memif_listener_t *listener = 0;
771 memif_pending_conn_t *pending_conn = 0;
773 memif_disconnect (vm, mif);
775 if (mif->listener_index != (uword) ~ 0)
777 listener = pool_elt_at_index (mm->listeners, mif->listener_index);
778 if (--listener->usage_counter == 0)
780 /* not used anymore -> remove the socket and pending connections */
783 pool_foreach (pending_conn, mm->pending_conns,
785 if (pending_conn->listener_index == mif->listener_index)
787 memif_remove_pending_conn (pending_conn);
792 unix_file_del (&unix_main,
793 unix_main.file_pool + listener->socket.index);
794 pool_put (mm->listeners, listener);
795 unlink ((char *) mif->socket_filename);
799 clib_spinlock_free (&mif->lockp);
801 mhash_unset (&mm->if_index_by_key, &mif->key, &mif->if_index);
802 vec_free (mif->socket_filename);
803 vec_free (mif->ring_data);
805 memset (mif, 0, sizeof (*mif));
806 pool_put (mm->interfaces, mif);
810 memif_worker_thread_enable ()
812 /* if worker threads are enabled, switch to polling mode */
816 vlib_node_set_state (this_vlib_main,
817 memif_input_node.index,
818 VLIB_NODE_STATE_POLLING);
825 memif_worker_thread_disable ()
830 vlib_node_set_state (this_vlib_main,
831 memif_input_node.index,
832 VLIB_NODE_STATE_INTERRUPT);
839 memif_create_if (vlib_main_t * vm, memif_create_if_args_t * args)
841 memif_main_t *mm = &memif_main;
842 vlib_thread_main_t *tm = vlib_get_thread_main ();
843 vnet_main_t *vnm = vnet_get_main ();
845 vnet_sw_interface_t *sw;
846 clib_error_t *error = 0;
850 p = mhash_get (&mm->if_index_by_key, &args->key);
852 return VNET_API_ERROR_SUBIF_ALREADY_EXISTS;
854 pool_get (mm->interfaces, mif);
855 memset (mif, 0, sizeof (*mif));
856 mif->key = args->key;
857 mif->if_index = mif - mm->interfaces;
858 mif->sw_if_index = mif->hw_if_index = mif->per_interface_next_index = ~0;
859 mif->listener_index = ~0;
860 mif->connection.index = mif->interrupt_line.index = ~0;
861 mif->connection.fd = mif->interrupt_line.fd = -1;
863 if (tm->n_vlib_mains > 1)
864 clib_spinlock_init (&mif->lockp);
866 if (!args->hw_addr_set)
868 f64 now = vlib_time_now (vm);
870 rnd = (u32) (now * 1e6);
871 rnd = random_u32 (&rnd);
873 memcpy (args->hw_addr + 2, &rnd, sizeof (rnd));
874 args->hw_addr[0] = 2;
875 args->hw_addr[1] = 0xfe;
878 error = ethernet_register_interface (vnm, memif_device_class.index,
879 mif->if_index, args->hw_addr,
881 memif_eth_flag_change);
885 clib_error_report (error);
886 ret = VNET_API_ERROR_SYSCALL_ERROR_1;
890 sw = vnet_get_hw_sw_interface (vnm, mif->hw_if_index);
891 mif->sw_if_index = sw->sw_if_index;
893 mif->log2_ring_size = args->log2_ring_size;
894 mif->buffer_size = args->buffer_size;
896 mif->num_s2m_rings = args->rx_queues;
897 mif->num_m2s_rings = args->tx_queues;
899 mhash_set_mem (&mm->if_index_by_key, &args->key, &mif->if_index, 0);
901 if (args->socket_filename != 0)
902 mif->socket_filename = args->socket_filename;
904 mif->socket_filename = vec_dup (mm->default_socket_filename);
906 args->sw_if_index = mif->sw_if_index;
910 struct sockaddr_un un = { 0 };
911 struct stat file_stat;
913 memif_listener_t *listener = 0;
915 if (stat ((char *) mif->socket_filename, &file_stat) == 0)
917 if (!S_ISSOCK (file_stat.st_mode))
920 ret = VNET_API_ERROR_SYSCALL_ERROR_2;
924 pool_foreach (listener, mm->listeners,
926 if (listener->sock_dev == file_stat.st_dev &&
927 listener->sock_ino == file_stat.st_ino)
929 /* attach memif to the existing listener */
930 mif->listener_index = listener->index;
931 ++listener->usage_counter;
936 unlink ((char *) mif->socket_filename);
939 pool_get (mm->listeners, listener);
940 memset (listener, 0, sizeof (*listener));
941 listener->socket.fd = -1;
942 listener->socket.index = ~0;
943 listener->index = listener - mm->listeners;
944 listener->usage_counter = 1;
946 if ((listener->socket.fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
948 ret = VNET_API_ERROR_SYSCALL_ERROR_3;
952 un.sun_family = AF_UNIX;
953 strncpy ((char *) un.sun_path, (char *) mif->socket_filename,
954 sizeof (un.sun_path) - 1);
956 if (setsockopt (listener->socket.fd, SOL_SOCKET, SO_PASSCRED,
957 &on, sizeof (on)) < 0)
959 ret = VNET_API_ERROR_SYSCALL_ERROR_4;
962 if (bind (listener->socket.fd, (struct sockaddr *) &un,
965 ret = VNET_API_ERROR_SYSCALL_ERROR_5;
968 if (listen (listener->socket.fd, 1) == -1)
970 ret = VNET_API_ERROR_SYSCALL_ERROR_6;
974 if (stat ((char *) mif->socket_filename, &file_stat) == -1)
976 ret = VNET_API_ERROR_SYSCALL_ERROR_7;
980 listener->sock_dev = file_stat.st_dev;
981 listener->sock_ino = file_stat.st_ino;
983 unix_file_t template = { 0 };
984 template.read_function = memif_conn_fd_accept_ready;
985 template.file_descriptor = listener->socket.fd;
986 template.private_data = listener->index;
987 listener->socket.index = unix_file_add (&unix_main, &template);
989 mif->listener_index = listener->index;
993 mif->flags |= MEMIF_IF_FLAG_IS_SLAVE;
997 /* use configured or generate random MAC address */
998 if (!args->hw_addr_set &&
999 tm->n_vlib_mains > 1 && pool_elts (mm->interfaces) == 1)
1000 memif_worker_thread_enable ();
1004 if (pool_elts (mm->interfaces) == 1)
1006 vlib_process_signal_event (vm, memif_process_node.index,
1007 MEMIF_PROCESS_EVENT_START, 0);
1012 if (mif->hw_if_index != ~0)
1014 ethernet_delete_interface (vnm, mif->hw_if_index);
1015 mif->hw_if_index = ~0;
1017 memif_close_if (mm, mif);
1022 memif_delete_if (vlib_main_t * vm, u64 key)
1024 vnet_main_t *vnm = vnet_get_main ();
1025 memif_main_t *mm = &memif_main;
1030 p = mhash_get (&mm->if_index_by_key, &key);
1033 DEBUG_LOG ("Memory interface with key 0x%" PRIx64 " does not exist",
1035 return VNET_API_ERROR_SYSCALL_ERROR_1;
1037 mif = pool_elt_at_index (mm->interfaces, p[0]);
1038 mif->flags |= MEMIF_IF_FLAG_DELETING;
1040 /* bring down the interface */
1041 vnet_sw_interface_set_flags (vnm, mif->sw_if_index, 0);
1043 hw_if_index = mif->hw_if_index;
1044 memif_close_if (mm, mif);
1046 /* remove the interface */
1047 ethernet_delete_interface (vnm, hw_if_index);
1048 if (pool_elts (mm->interfaces) == 0)
1050 vlib_process_signal_event (vm, memif_process_node.index,
1051 MEMIF_PROCESS_EVENT_STOP, 0);
1055 if (tm->n_vlib_mains > 1 && pool_elts (mm->interfaces) == 0)
1056 memif_worker_thread_disable ();
1062 static clib_error_t *
1063 memif_init (vlib_main_t * vm)
1065 memif_main_t *mm = &memif_main;
1066 vlib_thread_main_t *tm = vlib_get_thread_main ();
1067 vlib_thread_registration_t *tr;
1070 memset (mm, 0, sizeof (memif_main_t));
1072 mm->input_cpu_first_index = 0;
1073 mm->input_cpu_count = 1;
1075 /* initialize binary API */
1076 memif_plugin_api_hookup (vm);
1078 /* find out which cpus will be used for input */
1079 p = hash_get_mem (tm->thread_registrations_by_name, "workers");
1080 tr = p ? (vlib_thread_registration_t *) p[0] : 0;
1082 if (tr && tr->count > 0)
1084 mm->input_cpu_first_index = tr->first_index;
1085 mm->input_cpu_count = tr->count;
1088 mhash_init (&mm->if_index_by_key, sizeof (uword), sizeof (u64));
1090 vec_validate_aligned (mm->rx_buffers, tm->n_vlib_mains - 1,
1091 CLIB_CACHE_LINE_BYTES);
1093 /* set default socket filename */
1094 vec_validate (mm->default_socket_filename,
1095 strlen (MEMIF_DEFAULT_SOCKET_FILENAME));
1096 strncpy ((char *) mm->default_socket_filename,
1097 MEMIF_DEFAULT_SOCKET_FILENAME,
1098 vec_len (mm->default_socket_filename) - 1);
1103 VLIB_INIT_FUNCTION (memif_init);
1106 VLIB_PLUGIN_REGISTER () = {
1107 .version = VPP_BUILD_VER,
1108 .description = "Packet Memory Interface (experimetal)",
1113 * fd.io coding-style-patch-verification: ON
1116 * eval: (c-set-style "gnu")