+/*
+ * Returns an unused socket id, and ~0 if it can't find one.
+ */
+u32
+memif_get_unused_socket_id ()
+{
+ memif_main_t *mm = &memif_main;
+ uword *p;
+ int i, j;
+
+ static u32 seed = 0;
+ /* limit to 1M tries */
+ for (j = 0; j < 1 << 10; j++)
+ {
+ seed = random_u32 (&seed);
+ for (i = 0; i < 1 << 10; i++)
+ {
+ /* look around randomly generated id */
+ seed += (2 * (i % 2) - 1) * i;
+ if (seed == (u32) ~0)
+ continue;
+ p = hash_get (mm->socket_file_index_by_sock_id, seed);
+ if (!p)
+ return seed;
+ }
+ }
+
+ return ~0;
+}
+
+clib_error_t *
+memif_socket_filename_add_del (u8 is_add, u32 sock_id, char *sock_filename)
+{
+ memif_main_t *mm = &memif_main;
+ uword *p;
+ memif_socket_file_t *msf;
+ clib_error_t *err = 0;
+ char *dir = 0, *tmp;
+ u32 idx = 0;
+ u8 *name = 0;
+
+ /* allow adding socket id 0 */
+ if (sock_id == 0 && is_add == 0)
+ return vnet_error (VNET_ERR_INVALID_ARGUMENT, "cannot delete socket id 0");
+
+ if (sock_id == ~0)
+ return vnet_error (VNET_ERR_INVALID_ARGUMENT,
+ "socked id is not specified");
+
+ if (is_add == 0)
+ {
+ p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
+ if (!p)
+ /* Don't delete non-existent entries. */
+ return vnet_error (VNET_ERR_INVALID_ARGUMENT,
+ "socket file with id %u does not exist", sock_id);
+
+ msf = pool_elt_at_index (mm->socket_files, *p);
+ if (msf->ref_cnt > 0)
+ return vnet_error (VNET_ERR_UNEXPECTED_INTF_STATE,
+ "socket file '%s' is in use", msf->filename);
+
+ vec_free (msf->filename);
+ pool_put (mm->socket_files, msf);
+
+ hash_unset (mm->socket_file_index_by_sock_id, sock_id);
+
+ return 0;
+ }
+
+ if (sock_filename == 0 || sock_filename[0] == 0)
+ return vnet_error (VNET_ERR_INVALID_ARGUMENT,
+ "socket filename not specified");
+
+ if (clib_socket_prefix_is_valid (sock_filename))
+ {
+ name = format (0, "%s%c", sock_filename, 0);
+ }
+ else if (sock_filename[0] == '/')
+ {
+ name = format (0, "%s%c", sock_filename, 0);
+ }
+ else
+ {
+ /* copy runtime dir path */
+ vec_add (dir, vlib_unix_get_runtime_dir (),
+ strlen (vlib_unix_get_runtime_dir ()));
+ vec_add1 (dir, '/');
+
+ /* if sock_filename contains dirs, add them to path */
+ tmp = strrchr (sock_filename, '/');
+ if (tmp)
+ {
+ idx = tmp - sock_filename;
+ vec_add (dir, sock_filename, idx);
+ }
+
+ vec_add1 (dir, '\0');
+ /* create socket dir */
+ if ((err = vlib_unix_recursive_mkdir (dir)))
+ {
+ clib_error_free (err);
+ err = vnet_error (VNET_ERR_SYSCALL_ERROR_1,
+ "unable to create socket dir");
+ goto done;
+ }
+
+ name =
+ format (0, "%s/%s%c", vlib_unix_get_runtime_dir (), sock_filename, 0);
+ }
+
+ p = hash_get (mm->socket_file_index_by_sock_id, sock_id);
+ if (p)
+ {
+ msf = pool_elt_at_index (mm->socket_files, *p);
+ if (strcmp ((char *) msf->filename, (char *) name) == 0)
+ {
+ /* Silently accept identical "add". */
+ goto done;
+ }
+
+ /* But don't allow a direct add of a different filename. */
+ err = vnet_error (VNET_ERR_ENTRY_ALREADY_EXISTS, "entry already exists");
+ goto done;
+ }
+
+ pool_get (mm->socket_files, msf);
+ clib_memset (msf, 0, sizeof (memif_socket_file_t));
+
+ msf->filename = name;
+ msf->socket_id = sock_id;
+ name = 0;
+
+ hash_set (mm->socket_file_index_by_sock_id, sock_id, msf - mm->socket_files);
+
+done:
+ vec_free (name);
+ vec_free (dir);
+ return err;
+}
+
+clib_error_t *
+memif_delete_if (vlib_main_t *vm, memif_if_t *mif)