static void * search_ccmap(void *aux_) { struct ccmap_aux *aux = aux_; size_t i; if (mutation_frac) { for (i = 0; i < n_elems; i++) { uint32_t hash = hash_int(i, 0); if (random_uint32() < mutation_frac) { ovs_mutex_lock(&aux->mutex); uint32_t count = ccmap_find(aux->ccmap, hash); if (count) { ccmap_dec(aux->ccmap, hash); } ovs_mutex_unlock(&aux->mutex); } else { ignore(ccmap_find(aux->ccmap, hash)); } } } else { for (i = 0; i < n_elems; i++) { ignore(ccmap_find(aux->ccmap, hash_int(i, 0))); } } return NULL; }
static void time_timespec__(struct clock *c, struct timespec *ts) { bool slow_path; time_init(); atomic_read_relaxed(&c->slow_path, &slow_path); if (!slow_path) { xclock_gettime(c->id, ts); } else { struct timespec warp; struct timespec cache; bool stopped; ovs_mutex_lock(&c->mutex); stopped = c->stopped; warp = c->warp; cache = c->cache; ovs_mutex_unlock(&c->mutex); if (!stopped) { xclock_gettime(c->id, &cache); } timespec_add(ts, &cache, &warp); } }
/* Check whether a fatal signal has occurred and, if so, call the fatal signal * hooks and exit. * * This function is called automatically by poll_block(), but specialized * programs that may not always call poll_block() on a regular basis should * also call it periodically. (Therefore, any function with "block" in its * name should call fatal_signal_run() each time it is called, either directly * or through poll_block(), because such functions can only used by specialized * programs that can afford to block outside their main loop around * poll_block().) */ void fatal_signal_run(void) { sig_atomic_t sig_nr; fatal_signal_init(); sig_nr = stored_sig_nr; if (sig_nr != SIG_ATOMIC_MAX) { char namebuf[SIGNAL_NAME_BUFSIZE]; ovs_mutex_lock(&mutex); VLOG_WARN("terminating with signal %d (%s)", (int)sig_nr, signal_name(sig_nr, namebuf, sizeof namebuf)); call_hooks(sig_nr); /* Re-raise the signal with the default handling so that the program * termination status reflects that we were killed by this signal */ signal(sig_nr, SIG_DFL); raise(sig_nr); ovs_mutex_unlock(&mutex); OVS_NOT_REACHED(); } }
/* Unregisters 'file' from being unlinked when the program terminates via * exit() or a fatal signal. */ void fatal_signal_remove_file_to_unlink(const char *file) { fatal_signal_init(); ovs_mutex_lock(&mutex); sset_find_and_delete(&files, file); ovs_mutex_unlock(&mutex); }
static bool is_warped(const struct clock *c) { bool warped; ovs_mutex_lock(&c->mutex); warped = monotonic_clock.warp.tv_sec || monotonic_clock.warp.tv_nsec; ovs_mutex_unlock(&c->mutex); return warped; }
/* Registers 'file' to be unlinked when the program terminates via exit() or a * fatal signal. */ void fatal_signal_add_file_to_unlink(const char *file) { fatal_signal_init(); ovs_mutex_lock(&mutex); if (!added_hook) { added_hook = true; fatal_signal_add_hook(unlink_files, cancel_files, NULL, true); } sset_add(&files, file); ovs_mutex_unlock(&mutex); }
/* Registers 'hook_cb' to be called from inside poll_block() following a fatal * signal. 'hook_cb' does not need to be async-signal-safe. In a * multithreaded program 'hook_cb' might be called from any thread, with * threads other than the one running 'hook_cb' in unknown states. * * If 'run_at_exit' is true, 'hook_cb' is also called during normal process * termination, e.g. when exit() is called or when main() returns. * * If the current process forks, fatal_signal_fork() may be called to clear the * parent process's fatal signal hooks, so that 'hook_cb' is only called when * the child terminates, not when the parent does. When fatal_signal_fork() is * called, it calls the 'cancel_cb' function if it is nonnull, passing 'aux', * to notify that the hook has been canceled. This allows the hook to free * memory, etc. */ void fatal_signal_add_hook(void (*hook_cb)(void *aux), void (*cancel_cb)(void *aux), void *aux, bool run_at_exit) { fatal_signal_init(); ovs_mutex_lock(&mutex); ovs_assert(n_hooks < MAX_HOOKS); hooks[n_hooks].hook_cb = hook_cb; hooks[n_hooks].cancel_cb = cancel_cb; hooks[n_hooks].aux = aux; hooks[n_hooks].run_at_exit = run_at_exit; n_hooks++; ovs_mutex_unlock(&mutex); }
/* Starts a Netlink "dump" operation, by sending 'request' to the kernel on a * Netlink socket created with the given 'protocol', and initializes 'dump' to * reflect the state of the operation. * * 'request' must contain a Netlink message. Before sending the message, * nlmsg_len will be finalized to match request->size, and nlmsg_pid will be * set to the Netlink socket's pid. NLM_F_DUMP and NLM_F_ACK will be set in * nlmsg_flags. * * The design of this Netlink socket library ensures that the dump is reliable. * * This function provides no status indication. nl_dump_done() provides an * error status for the entire dump operation. * * The caller must eventually destroy 'request'. */ void nl_dump_start(struct nl_dump *dump, int protocol, const struct ofpbuf *request) { nl_msg_nlmsghdr(request)->nlmsg_flags |= NLM_F_DUMP | NLM_F_ACK; ovs_mutex_init(&dump->mutex); ovs_mutex_lock(&dump->mutex); dump->status = nl_pool_alloc(protocol, &dump->sock); if (!dump->status) { dump->status = nl_sock_send__(dump->sock, request, nl_sock_allocate_seq(dump->sock, 1), true); } dump->nl_seq = nl_msg_nlmsghdr(request)->nlmsg_seq; ovs_mutex_unlock(&dump->mutex); }
/* Like fatal_signal_remove_file_to_unlink(), but also unlinks 'file'. * Returns 0 if successful, otherwise a positive errno value. */ int fatal_signal_unlink_file_now(const char *file) { int error; fatal_signal_init(); ovs_mutex_lock(&mutex); error = unlink(file) ? errno : 0; if (error) { VLOG_WARN("could not unlink \"%s\" (%s)", file, ovs_strerror(error)); } fatal_signal_remove_file_to_unlink(file); ovs_mutex_unlock(&mutex); return error; }
/* Generates a new random UUID in 'uuid'. * * We go to some trouble to ensure as best we can that the generated UUID has * these properties: * * - Uniqueness. The random number generator is seeded using both the * system clock and the system random number generator, plus a few * other identifiers, which is about as good as we can get in any kind * of simple way. * * - Unpredictability. In some situations it could be bad for an * adversary to be able to guess the next UUID to be generated with some * probability of success. This property may or may not be important * for our purposes, but it is better if we can get it. * * To ensure both of these, we start by taking our seed data and passing it * through SHA-1. We use the result as an AES-128 key. We also generate a * random 16-byte value[*] which we then use as the counter for CTR mode. To * generate a UUID in a manner compliant with the above goals, we merely * increment the counter and encrypt it. * * [*] It is not actually important that the initial value of the counter be * random. AES-128 in counter mode is secure either way. */ void uuid_generate(struct uuid *uuid) { static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER; uint64_t copy[2]; uuid_init(); /* Copy out the counter's current value, then increment it. */ ovs_mutex_lock(&mutex); copy[0] = counter[0]; copy[1] = counter[1]; if (++counter[1] == 0) { counter[0]++; } ovs_mutex_unlock(&mutex); /* AES output is exactly 16 bytes, so we encrypt directly into 'uuid'. */ aes128_encrypt(&key, copy, uuid); uuid_set_bits_v4(uuid); }
/* Creates a new netlink socket for the given netlink 'protocol' * (NETLINK_ROUTE, NETLINK_GENERIC, ...). Returns 0 and sets '*sockp' to the * new socket if successful, otherwise returns a positive errno value. */ int nl_sock_create(int protocol, struct nl_sock **sockp) { static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; struct nl_sock *sock; #ifndef _WIN32 struct sockaddr_nl local, remote; #endif socklen_t local_size; int rcvbuf; int retval = 0; if (ovsthread_once_start(&once)) { int save_errno = errno; errno = 0; max_iovs = sysconf(_SC_UIO_MAXIOV); if (max_iovs < _XOPEN_IOV_MAX) { if (max_iovs == -1 && errno) { VLOG_WARN("sysconf(_SC_UIO_MAXIOV): %s", ovs_strerror(errno)); } max_iovs = _XOPEN_IOV_MAX; } else if (max_iovs > MAX_IOVS) { max_iovs = MAX_IOVS; } errno = save_errno; ovsthread_once_done(&once); } *sockp = NULL; sock = xmalloc(sizeof *sock); #ifdef _WIN32 sock->handle = CreateFileA("\\\\.\\OpenVSwitchDevice", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); int last_error = GetLastError(); if (sock->handle == INVALID_HANDLE_VALUE) { VLOG_ERR("fcntl: %s", ovs_strerror(last_error)); goto error; } #else sock->fd = socket(AF_NETLINK, SOCK_RAW, protocol); if (sock->fd < 0) { VLOG_ERR("fcntl: %s", ovs_strerror(errno)); goto error; } #endif sock->protocol = protocol; sock->next_seq = 1; rcvbuf = 1024 * 1024; #ifdef _WIN32 sock->rcvbuf = rcvbuf; ovs_mutex_lock(&portid_mutex); sock->pid = portid_next(); set_sock_pid_in_kernel(sock->handle, sock->pid); ovs_mutex_unlock(&portid_mutex); #else if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof rcvbuf)) { /* Only root can use SO_RCVBUFFORCE. Everyone else gets EPERM. * Warn only if the failure is therefore unexpected. */ if (errno != EPERM) { VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed " "(%s)", rcvbuf, ovs_strerror(errno)); } } retval = get_socket_rcvbuf(sock->fd); if (retval < 0) { retval = -retval; goto error; } sock->rcvbuf = retval; /* Connect to kernel (pid 0) as remote address. */ memset(&remote, 0, sizeof remote); remote.nl_family = AF_NETLINK; remote.nl_pid = 0; if (connect(sock->fd, (struct sockaddr *) &remote, sizeof remote) < 0) { VLOG_ERR("connect(0): %s", ovs_strerror(errno)); goto error; } /* Obtain pid assigned by kernel. */ local_size = sizeof local; if (getsockname(sock->fd, (struct sockaddr *) &local, &local_size) < 0) { VLOG_ERR("getsockname: %s", ovs_strerror(errno)); goto error; } if (local_size < sizeof local || local.nl_family != AF_NETLINK) { VLOG_ERR("getsockname returned bad Netlink name"); retval = EINVAL; goto error; } sock->pid = local.nl_pid; #endif *sockp = sock; return 0; error: if (retval == 0) { retval = errno; if (retval == 0) { retval = EINVAL; } } #ifdef _WIN32 if (sock->handle != INVALID_HANDLE_VALUE) { CloseHandle(sock->handle); } #else if (sock->fd >= 0) { close(sock->fd); } #endif free(sock); return retval; }