/* Execute a group entry of type FAILFAST. */ static void execute_ff(struct group_entry *entry, struct packet *pkt) { size_t b = select_from_ff_group(entry); if (b != -1) { struct ofl_bucket *bucket = entry->desc->buckets[b]; struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); VLOG_DBG_RL(LOG_MODULE, &rl, "Writing bucket: %s.", b); free(b); } action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); entry->stats->byte_count += p->buffer->size; entry->stats->packet_count++; entry->stats->counters[b]->byte_count += p->buffer->size; entry->stats->counters[b]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ action_set_execute(p->action_set, p, 0xffffffffffffffff); packet_destroy(p); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); } }
static void jsonrpc_log_msg(const struct jsonrpc *rpc, const char *title, const struct jsonrpc_msg *msg) { if (VLOG_IS_DBG_ENABLED()) { struct ds s = DS_EMPTY_INITIALIZER; if (msg->method) { ds_put_format(&s, ", method=\"%s\"", msg->method); } if (msg->params) { ds_put_cstr(&s, ", params="); json_to_ds(msg->params, 0, &s); } if (msg->result) { ds_put_cstr(&s, ", result="); json_to_ds(msg->result, 0, &s); } if (msg->error) { ds_put_cstr(&s, ", error="); json_to_ds(msg->error, 0, &s); } if (msg->id) { ds_put_cstr(&s, ", id="); json_to_ds(msg->id, 0, &s); } VLOG_DBG("%s: %s %s%s", rpc->name, title, jsonrpc_msg_type_to_string(msg->type), ds_cstr(&s)); ds_destroy(&s); } }
/* Executes a group entry of type ALL. */ static void execute_all(struct group_entry *entry, struct packet *pkt) { size_t i; /* TODO Zoltan: Currently packets are always cloned. However it should * be possible to see if cloning is necessary, or not, based on bucket actions. */ for (i=0; i<entry->desc->buckets_num; i++) { struct ofl_bucket *bucket = entry->desc->buckets[i]; struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); VLOG_DBG_RL(LOG_MODULE, &rl, "Writing bucket: %s.", b); free(b); } action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); entry->stats->byte_count += p->buffer->size; entry->stats->packet_count++; entry->stats->counters[i]->byte_count += p->buffer->size; entry->stats->counters[i]->packet_count++; /* Cookie field is set 0xffffffffffffffff because we cannot associate to any particular flow */ action_set_execute(p->action_set, p, 0xffffffffffffffff); packet_destroy(p); } }
/* Execute a group entry of type INDIRECT. */ static void execute_indirect(struct group_entry *entry, struct packet *pkt) { if (entry->desc->buckets_num > 0) { struct ofl_bucket *bucket = entry->desc->buckets[0]; struct packet *p = packet_clone(pkt); if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *b = ofl_structs_bucket_to_string(bucket, entry->dp->exp); VLOG_DBG_RL(LOG_MODULE, &rl, "Writing bucket: %s.", b); free(b); } action_set_write_actions(p->action_set, bucket->actions_num, bucket->actions); entry->stats->byte_count += p->buffer->size; entry->stats->packet_count++; entry->stats->counters[0]->byte_count += p->buffer->size; entry->stats->counters[0]->packet_count++; action_set_execute(p->action_set, p); packet_destroy(p); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "No bucket in group."); } }
/* Prepare to start a process whose command-line arguments are given by the * null-terminated 'argv' array. Returns 0 if successful, otherwise a * positive errno value. */ static int process_prestart(char **argv) { char *binary; process_init(); /* Log the process to be started. */ if (VLOG_IS_DBG_ENABLED()) { char *args = process_escape_args(argv); VLOG_DBG("starting subprocess: %s", args); free(args); } /* execvp() will search PATH too, but the error in that case is more * obscure, since it is only reported post-fork. */ binary = process_search_path(argv[0]); if (!binary) { VLOG_ERR("%s not found in PATH", argv[0]); return ENOENT; } free(binary); return 0; }
/* Causes the following call to poll_block() to block for no more than 'msec' * milliseconds. If 'msec' is nonpositive, the following call to poll_block() * will not block at all. * * The timer registration is one-shot: only the following call to poll_block() * is affected. The timer will need to be re-registered after poll_block() is * called if it is to persist. */ void poll_timer_wait(int msec) { if (timeout < 0 || msec < timeout) { timeout = MAX(0, msec); if (VLOG_IS_DBG_ENABLED()) { backtrace_capture(&timeout_backtrace); } } }
/* Creates and returns a new poll_waiter for 'fd' and 'events'. */ static struct poll_waiter * new_waiter(int fd, short int events) { struct poll_waiter *waiter = xcalloc(1, sizeof *waiter); assert(fd >= 0); waiter->fd = fd; waiter->events = events; if (VLOG_IS_DBG_ENABLED()) { waiter->backtrace = xmalloc(sizeof *waiter->backtrace); backtrace_capture(waiter->backtrace); } list_push_back(&waiters, &waiter->node); n_waiters++; return waiter; }
/* Processes 'msg', which should be an OpenFlow received on 'rconn', according * to the learning switch state in 'sw'. The most likely result of processing * is that flow-setup and packet-out OpenFlow messages will be sent out on * 'rconn'. */ static void lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg) { enum ofptype type; struct ofpbuf b; b = *msg; if (ofptype_pull(&type, &b)) { return; } if (sw->state == S_FEATURES_REPLY && type != OFPTYPE_ECHO_REQUEST && type != OFPTYPE_FEATURES_REPLY) { return; } if (type == OFPTYPE_ECHO_REQUEST) { process_echo_request(sw, msg->data); } else if (type == OFPTYPE_FEATURES_REPLY) { if (sw->state == S_FEATURES_REPLY) { if (!process_switch_features(sw, msg->data)) { sw->state = S_SWITCHING; } else { rconn_disconnect(sw->rconn); } } } else if (type == OFPTYPE_PACKET_IN) { process_packet_in(sw, msg->data); } else if (type == OFPTYPE_FLOW_REMOVED) { /* Nothing to do. */ } else if (VLOG_IS_DBG_ENABLED()) { char *s = ofp_to_string(msg->data, msg->size, 2); VLOG_DBG_RL(&rl, "%016llx: OpenFlow packet ignored: %s", sw->datapath_id, s); free(s); } }
void pipeline_process_packet(struct pipeline *pl, struct packet *pkt) { struct flow_table *table, *next_table; if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *pkt_str = packet_to_string(pkt); VLOG_DBG_RL(LOG_MODULE, &rl, "processing packet: %s", pkt_str); free(pkt_str); } if (!packet_handle_std_is_ttl_valid(pkt->handle_std)) { if ((pl->dp->config.flags & OFPC_INVALID_TTL_TO_CONTROLLER) != 0) { VLOG_DBG_RL(LOG_MODULE, &rl, "Packet has invalid TTL, sending to controller."); send_packet_to_controller(pl, pkt, 0/*table_id*/, OFPR_INVALID_TTL); } else { VLOG_DBG_RL(LOG_MODULE, &rl, "Packet has invalid TTL, dropping."); } packet_destroy(pkt); return; } next_table = pl->tables[0]; while (next_table != NULL) { struct flow_entry *entry; VLOG_DBG_RL(LOG_MODULE, &rl, "trying table %u.", next_table->stats->table_id); pkt->table_id = next_table->stats->table_id; table = next_table; next_table = NULL; entry = flow_table_lookup(table, pkt); if (entry != NULL) { if (VLOG_IS_DBG_ENABLED(LOG_MODULE)) { char *m = ofl_structs_flow_stats_to_string(entry->stats, pkt->dp->exp); VLOG_DBG_RL(LOG_MODULE, &rl, "found matching entry: %s.", m); free(m); } execute_entry(pl, entry, &next_table, &pkt); /* Packet could be destroyed by a meter instruction */ if (!pkt) return; if (next_table == NULL) { /* Cookie field is set 0xffffffffffffffff because we cannot associate it to any particular flow */ action_set_execute(pkt->action_set, pkt, 0xffffffffffffffff); packet_destroy(pkt); return; } } else { /* OpenFlow 1.3 default behavior on a table miss */ VLOG_DBG_RL(LOG_MODULE, &rl, "No matching entry found. Dropping packet."); packet_destroy(pkt); return; } } VLOG_WARN_RL(LOG_MODULE, &rl, "Reached outside of pipeline processing cycle."); }
static int new_ssl_stream(const char *name, int fd, enum session_type type, enum ssl_state state, struct stream **streamp) { struct ssl_stream *sslv; SSL *ssl = NULL; int retval; /* Check for all the needful configuration. */ retval = 0; if (!private_key.read) { VLOG_ERR("Private key must be configured to use SSL"); retval = ENOPROTOOPT; } if (!certificate.read) { VLOG_ERR("Certificate must be configured to use SSL"); retval = ENOPROTOOPT; } if (!ca_cert.read && verify_peer_cert && !bootstrap_ca_cert) { VLOG_ERR("CA certificate must be configured to use SSL"); retval = ENOPROTOOPT; } if (!retval && !SSL_CTX_check_private_key(ctx)) { VLOG_ERR("Private key does not match certificate public key: %s", ERR_error_string(ERR_get_error(), NULL)); retval = ENOPROTOOPT; } if (retval) { goto error; } /* Disable Nagle. * On windows platforms, this can only be called upon TCP connected. */ if (state == STATE_SSL_CONNECTING) { setsockopt_tcp_nodelay(fd); } /* Create and configure OpenSSL stream. */ ssl = SSL_new(ctx); if (ssl == NULL) { VLOG_ERR("SSL_new: %s", ERR_error_string(ERR_get_error(), NULL)); retval = ENOPROTOOPT; goto error; } if (SSL_set_fd(ssl, fd) == 0) { VLOG_ERR("SSL_set_fd: %s", ERR_error_string(ERR_get_error(), NULL)); retval = ENOPROTOOPT; goto error; } if (!verify_peer_cert || (bootstrap_ca_cert && type == CLIENT)) { SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); } /* Create and return the ssl_stream. */ sslv = xmalloc(sizeof *sslv); stream_init(&sslv->stream, &ssl_stream_class, EAGAIN, name); sslv->state = state; sslv->type = type; sslv->fd = fd; sslv->ssl = ssl; sslv->txbuf = NULL; sslv->rx_want = sslv->tx_want = SSL_NOTHING; sslv->session_nr = next_session_nr++; sslv->n_head = 0; if (VLOG_IS_DBG_ENABLED()) { SSL_set_msg_callback(ssl, ssl_protocol_cb); SSL_set_msg_callback_arg(ssl, sslv); } *streamp = &sslv->stream; return 0; error: if (ssl) { SSL_free(ssl); } closesocket(fd); return retval; }
/* Blocks until one or more of the events registered with poll_fd_wait() * occurs, or until the minimum duration registered with poll_timer_wait() * elapses, or not at all if poll_immediate_wake() has been called. * * Also executes any autonomous subroutines registered with poll_fd_callback(), * if their file descriptors have become ready. */ void poll_block(void) { static struct pollfd *pollfds; static size_t max_pollfds; struct poll_waiter *pw; struct list *node; int n_pollfds; int retval; assert(!running_cb); if (max_pollfds < n_waiters) { max_pollfds = n_waiters; pollfds = xrealloc(pollfds, max_pollfds * sizeof *pollfds); } n_pollfds = 0; LIST_FOR_EACH (pw, struct poll_waiter, node, &waiters) { pw->pollfd = &pollfds[n_pollfds]; pollfds[n_pollfds].fd = pw->fd; pollfds[n_pollfds].events = pw->events; pollfds[n_pollfds].revents = 0; n_pollfds++; } retval = time_poll(pollfds, n_pollfds, timeout); if (retval < 0) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_ERR_RL(&rl, "poll: %s", strerror(-retval)); } else if (!retval && VLOG_IS_DBG_ENABLED()) { log_wakeup(&timeout_backtrace, "%d-ms timeout", timeout); } for (node = waiters.next; node != &waiters; ) { pw = CONTAINER_OF(node, struct poll_waiter, node); if (!pw->pollfd || !pw->pollfd->revents) { if (pw->function) { node = node->next; continue; } } else { if (VLOG_IS_DBG_ENABLED()) { log_wakeup(pw->backtrace, "%s%s%s%s%s on fd %d", pw->pollfd->revents & POLLIN ? "[POLLIN]" : "", pw->pollfd->revents & POLLOUT ? "[POLLOUT]" : "", pw->pollfd->revents & POLLERR ? "[POLLERR]" : "", pw->pollfd->revents & POLLHUP ? "[POLLHUP]" : "", pw->pollfd->revents & POLLNVAL ? "[POLLNVAL]" : "", pw->fd); } if (pw->function) { #ifndef NDEBUG running_cb = pw; #endif pw->function(pw->fd, pw->pollfd->revents, pw->aux); #ifndef NDEBUG running_cb = NULL; #endif } } node = node->next; poll_cancel(pw); } timeout = -1; timeout_backtrace.n_frames = 0; }
static int new_ssl_stream(const char *name, int fd, enum session_type type, enum ssl_state state, const struct sockaddr_in *remote, struct stream **streamp) { struct sockaddr_in local; socklen_t local_len = sizeof local; struct ssl_stream *sslv; SSL *ssl = NULL; int on = 1; int retval; /* Check for all the needful configuration. */ retval = 0; if (!private_key.read) { VLOG_ERR("Private key must be configured to use SSL"); retval = ENOPROTOOPT; } if (!certificate.read) { VLOG_ERR("Certificate must be configured to use SSL"); retval = ENOPROTOOPT; } if (!ca_cert.read && verify_peer_cert && !bootstrap_ca_cert) { VLOG_ERR("CA certificate must be configured to use SSL"); retval = ENOPROTOOPT; } if (!retval && !SSL_CTX_check_private_key(ctx)) { VLOG_ERR("Private key does not match certificate public key: %s", ERR_error_string(ERR_get_error(), NULL)); retval = ENOPROTOOPT; } if (retval) { goto error; } /* Get the local IP and port information */ retval = getsockname(fd, (struct sockaddr *) &local, &local_len); if (retval) { memset(&local, 0, sizeof local); } /* Disable Nagle. */ retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on); if (retval) { VLOG_ERR("%s: setsockopt(TCP_NODELAY): %s", name, strerror(errno)); retval = errno; goto error; } /* Create and configure OpenSSL stream. */ ssl = SSL_new(ctx); if (ssl == NULL) { VLOG_ERR("SSL_new: %s", ERR_error_string(ERR_get_error(), NULL)); retval = ENOPROTOOPT; goto error; } if (SSL_set_fd(ssl, fd) == 0) { VLOG_ERR("SSL_set_fd: %s", ERR_error_string(ERR_get_error(), NULL)); retval = ENOPROTOOPT; goto error; } if (!verify_peer_cert || (bootstrap_ca_cert && type == CLIENT)) { SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); } /* Create and return the ssl_stream. */ sslv = xmalloc(sizeof *sslv); stream_init(&sslv->stream, &ssl_stream_class, EAGAIN, name); stream_set_remote_ip(&sslv->stream, remote->sin_addr.s_addr); stream_set_remote_port(&sslv->stream, remote->sin_port); stream_set_local_ip(&sslv->stream, local.sin_addr.s_addr); stream_set_local_port(&sslv->stream, local.sin_port); sslv->state = state; sslv->type = type; sslv->fd = fd; sslv->ssl = ssl; sslv->txbuf = NULL; sslv->rx_want = sslv->tx_want = SSL_NOTHING; sslv->session_nr = next_session_nr++; sslv->n_head = 0; if (VLOG_IS_DBG_ENABLED()) { SSL_set_msg_callback(ssl, ssl_protocol_cb); SSL_set_msg_callback_arg(ssl, sslv); } *streamp = &sslv->stream; return 0; error: if (ssl) { SSL_free(ssl); } close(fd); return retval; }