Esempio n. 1
0
bool
discovery_run(struct discovery *d, char **controller_name)
{
    if (!d->dhcp) {
        *controller_name = NULL;
        return true;
    }

    dhclient_run(d->dhcp);
    if (!dhclient_changed(d->dhcp)) {
        return false;
    }

    dhclient_configure_netdev(d->dhcp);
    if (d->s->update_resolv_conf) {
        dhclient_update_resolv_conf(d->dhcp);
    }

    if (dhclient_is_bound(d->dhcp)) {
        *controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp),
                                               DHCP_CODE_OFP_CONTROLLER_VCONN);
        VLOG_INFO(LOG_MODULE, "%s: discovered controller", *controller_name);
        d->n_changes++;
    } else {
        *controller_name = NULL;
        if (d->n_changes) {
            VLOG_INFO(LOG_MODULE, "discovered controller no longer available");
            d->n_changes++;
        }
    }
    return true;
}
Esempio n. 2
0
File: dpdk.c Progetto: shettyg/ovs
void
dpdk_init(const struct smap *ovs_other_config)
{
    static bool enabled = false;

    if (enabled || !ovs_other_config) {
        return;
    }

    if (smap_get_bool(ovs_other_config, "dpdk-init", false)) {
        static struct ovsthread_once once_enable = OVSTHREAD_ONCE_INITIALIZER;

        if (ovsthread_once_start(&once_enable)) {
            VLOG_INFO("DPDK Enabled - initializing...");
            dpdk_init__(ovs_other_config);
            enabled = true;
            VLOG_INFO("DPDK Enabled - initialized");
            ovsthread_once_done(&once_enable);
        }
    } else {
        static struct ovsthread_once once_disable = OVSTHREAD_ONCE_INITIALIZER;
        if (ovsthread_once_start(&once_disable)) {
            VLOG_INFO("DPDK Disabled - Use other_config:dpdk-init to enable");
            ovsthread_once_done(&once_disable);
        }
    }
}
Esempio n. 3
0
void *pe_workers_fetch_flow(void *arg) {
    static char mod[] = "pe_workers_fetch_flow";
    pe_worker_t *this_worker = (pe_worker_t *) arg;
    void *work_item = NULL;

    DBUG_ENTER(mod);

    VLOG_INFO("Thread %i (%p) going to work.\n",this_worker->index,
                                                &this_worker->thread); 

    /* infinite loop to process work items */
    for(;;) {
        DBUG_PRINT("\nDEBUG ",("Thread %i (%d) calling ring_buffer_pop\n",
                               this_worker->index,
                               &this_worker->thread));
        work_item = ring_buffer_pop();
        DBUG_PRINT("\nDEBUG ",("Thread %i (%d) popped %p\n",
                               this_worker->index,
                               &this_worker->thread,
                               work_item)); 
        if (pe_get_crew_quit_status() == true) {
            VLOG_INFO("Thread %i got quit\n",this_worker->index);
            break;
        }
        pe_translate(work_item);
    }

    VLOG_INFO("Thread %i (%p) leaving work.\n",this_worker->index,
                                                this_worker->thread); 
    DBUG_LEAVE;
    pthread_exit((void *) NULL);
}
Esempio n. 4
0
static struct jsonrpc *
open_jsonrpc(const char *server)
{
    struct stream *stream;
    int error;

    error = stream_open_block(jsonrpc_stream_open(server, &stream,
                              DSCP_DEFAULT), &stream);
    if (error == EAFNOSUPPORT) {
        struct pstream *pstream;

        error = jsonrpc_pstream_open(server, &pstream, DSCP_DEFAULT);
        if (error) {
            ovs_fatal(error, "failed to connect or listen to \"%s\"", server);
        }

        VLOG_INFO("%s: waiting for connection...", server);
        error = pstream_accept_block(pstream, &stream);
        if (error) {
            ovs_fatal(error, "failed to accept connection on \"%s\"", server);
        }

        pstream_close(pstream);
    } else if (error) {
        ovs_fatal(error, "failed to connect to \"%s\"", server);
    }

    return jsonrpc_open(stream);
}
static void
failover_periodic_cb(void *context_)
{
	struct failover_context *context = context_;
	char *curr_peer = NULL;
	char *prev_peer = NULL;

	if (rconn_is_connected(context->remote_rconn))
		return;

	if (!is_timed_out(context->peers[context->index],
			  context->settings->max_backoff)) {
		return;
	}

	rconn_disconnect(context->remote_rconn);
	prev_peer = (char *)context->settings->controller_names[context->index];
	context->index = (context->index + 1)
		% context->settings->num_controllers;
	curr_peer = (char *)context->settings->controller_names[context->index];
	rconn_connect(context->remote_rconn,
		      context->settings->controller_names[context->index]);
	context->peers[context->index]->epoch = time_now();
	VLOG_INFO("Switching over to %s, from %s", curr_peer, prev_peer);
}
Esempio n. 6
0
/*-----------------------------------------------------------------------------
| Function: vtysh_ovsdb_config_logmsg
| Responsibility : logs info/dbg/err/warn level message
| Parameters: loglevel - logging level INFO/DBG/ERR/WARN
|             fmt - log message foramt
|             elipses - variable args
| Return: void
-----------------------------------------------------------------------------*/
void
vtysh_ovsdb_config_logmsg(int loglevel, char *fmt, ...)
{

  va_list args;
  va_start(args, fmt);

  switch (loglevel) {

    case VTYSH_OVSDB_CONFIG_ERR:
          VLOG_ERR(fmt, args);
          break;
    case VTYSH_OVSDB_CONFIG_WARN:
          VLOG_WARN(fmt, args);
          break;
    case VTYSH_OVSDB_CONFIG_INFO:
          VLOG_INFO(fmt, args);
          break;
    case VTYSH_OVSDB_CONFIG_DBG:
          VLOG_DBG(fmt, args);
          break;
    default :
          break;
  }
  va_end(args);
}
Esempio n. 7
0
int main() {
  eventrpc::SetProgramName("test");
  VLOG_INFO() << "test vlog";
  LOG_INFO() << "test log";

  return 0;
}
Esempio n. 8
0
uint32_t get_next_seqnum(struct tcp_buf *tcp_buffer, int seq, struct ofpbuf *packet, bool loss_recovery){
    unsigned int size;
    uint8_t tcp_flags;
    struct tcp_header *tcp;

    tcp = ofpbuf_l4(packet);
    tcp_flags = TCP_FLAGS(tcp->tcp_ctl);    
    size = get_tcp_payload_size(packet);

    // Sliding the expected seq forward to recover from the probable burst
    // of losts packets
    if(loss_recovery){
        return (seq + (get_tcp_payload_size(packet)*LOSS_RECOVERY_SLIDING)) % 0xFFFFFFFF;
    }
    else {
        if(tcp_flags & TCP_FIN){
            VLOG_INFO("Last packet above was FIN");
            tcp_buffer->fin_state = true;
            return (seq + size + 1) % 0xFFFFFFFF;
        }
        else{
            return (seq + size) % 0xFFFFFFFF;
        }
    }
}
Esempio n. 9
0
void
handle_acl_log(const struct flow *headers, struct ofpbuf *userdata)
{
    if (!VLOG_IS_INFO_ENABLED()) {
        return;
    }

    struct log_pin_header *lph = ofpbuf_try_pull(userdata, sizeof *lph);
    if (!lph) {
        VLOG_WARN("log data missing");
        return;
    }

    size_t name_len = userdata->size;
    char *name = name_len ? xmemdup0(userdata->data, name_len) : NULL;

    struct ds ds = DS_EMPTY_INITIALIZER;
    ds_put_cstr(&ds, "name=");
    json_string_escape(name_len ? name : "<unnamed>", &ds);
    ds_put_format(&ds, ", verdict=%s, severity=%s: ",
                  log_verdict_to_string(lph->verdict),
                  log_severity_to_string(lph->severity));
    flow_format(&ds, headers, NULL);

    VLOG_INFO("%s", ds_cstr(&ds));
    ds_destroy(&ds);
    free(name);
}
Esempio n. 10
0
void
plugins_destroy(void)
{
    PLUGINS_CALL(destroy);
    lt_dlinterface_free(interface_id);
    lt_dlexit();
    VLOG_INFO("Destroyed all plugins");
}
Esempio n. 11
0
/* If 'rc' is connected, forces it to drop the connection and reconnect. */
void
rconn_reconnect(struct rconn *rc)
{
    if (rc->state & (S_ACTIVE | S_IDLE)) {
        VLOG_INFO("%s: disconnecting", rc->name);
        disconnect(rc, 0);
    }
}
Esempio n. 12
0
 bool HandleConnection(bool is_connected) {
   if (!is_connected) {
     return false;
   }
   for (uint32 i = 0; i < kMaxConnection; ++i) {
     echo::EchoRequest request;
     string content = StringUtility::ConvertUint32ToString(i);
     VLOG_INFO() << "i: " << i;
     request.set_message(content);
     channel_->SendPacket(CMSG_ECHO, &request);
   }
   return true;
 }
Esempio n. 13
0
static int
plugins_open_plugin(const char *filename, void *data)
{
    struct plugin_class *plcl;
    lt_dlhandle handle;

    if (!(handle = lt_dlopenadvise(filename, *(lt_dladvise *)data))) {
        VLOG_ERR("Failed loading %s: %s", filename, lt_dlerror());
        return 0;
    }

    if (!(plcl = (struct plugin_class *)malloc(sizeof(struct plugin_class)))) {
        VLOG_ERR("Couldn't allocate plugin class");
        goto err_plugin_class;
    }

    if (!(plcl->init = lt_dlsym(handle, "init")) ||
        !(plcl->run = lt_dlsym(handle, "run")) ||
        !(plcl->wait = lt_dlsym(handle, "wait")) ||
        !(plcl->destroy = lt_dlsym(handle, "destroy"))) {
            VLOG_ERR("Couldn't initialize the interface for %s", filename);
            goto err_dlsym;
    }

    // The following APIs are optional, so don't fail if they are missing.
    plcl->netdev_register = lt_dlsym(handle, "netdev_register");
    plcl->ofproto_register = lt_dlsym(handle, "ofproto_register");
    plcl->bufmon_register = lt_dlsym(handle, "bufmon_register");


    if (lt_dlcaller_set_data(interface_id, handle, plcl)) {
        VLOG_ERR("plugin %s initialized twice? must be a bug", filename);
        goto err_set_data;
    }

    plcl->init();

    VLOG_INFO("Loaded plugin library %s", filename);
    return 0;

err_set_data:
err_dlsym:
    free(plcl);

err_plugin_class:
    if (lt_dlclose(handle)) {
        VLOG_ERR("Couldn't dlclose %s", filename);
    }

    return 0;
}
Esempio n. 14
0
static char *
read_host_uuid(void)
{
    static const char filename[] = "/etc/xensource-inventory";
    char line[128];
    FILE *file;

    file = fopen(filename, "r");
    if (!file) {
        if (errno == ENOENT) {
            VLOG_DBG("not running on a XenServer");
        } else {
            VLOG_INFO("%s: open: %s", filename, ovs_strerror(errno));
        }
        return NULL;
    }

    while (fgets(line, sizeof line, file)) {
        static const char leader[] = "INSTALLATION_UUID='";
        const int leader_len = strlen(leader);
        const int uuid_len = 36;
        static const char trailer[] = "'\n";
        const int trailer_len = strlen(trailer);

        if (strlen(line) == leader_len + uuid_len + trailer_len
            && !memcmp(line, leader, leader_len)
            && !memcmp(line + leader_len + uuid_len, trailer, trailer_len)) {
            char *host_uuid = xmemdup0(line + leader_len, uuid_len);
            VLOG_INFO("running on XenServer, host-uuid %s", host_uuid);
            fclose(file);
            return host_uuid;
        }
    }
    fclose(file);
    VLOG_ERR("%s: INSTALLATION_UUID not found", filename);
    return NULL;
}
Esempio n. 15
0
File: dpdk.c Progetto: shettyg/ovs
static int
process_vhost_flags(char *flag, char *default_val, int size,
                    const struct smap *ovs_other_config,
                    char **new_val)
{
    const char *val;
    int changed = 0;

    val = smap_get(ovs_other_config, flag);

    /* Process the vhost-sock-dir flag if it is provided, otherwise resort to
     * default value.
     */
    if (val && (strlen(val) <= size)) {
        changed = 1;
        *new_val = xstrdup(val);
        VLOG_INFO("User-provided %s in use: %s", flag, *new_val);
    } else {
        VLOG_INFO("No %s provided - defaulting to %s", flag, default_val);
        *new_val = default_val;
    }

    return changed;
}
Esempio n. 16
0
TEST_F(EchoMessageTest, Test1) {
  Dispatcher client_dispatcher;
  Monitor monitor;
  MessageChannel channel("127.0.0.1", 21118);
  EchoClientMessageHandler handler(&channel, &monitor);
  channel.set_dispatcher(&client_dispatcher);
  channel.set_message_handler(&handler);
  client_dispatcher.Start();
  channel.Connect();
  monitor.Wait();
  ASSERT_EQ(kCount, kMaxConnection);
  VLOG_INFO() << "out of wait";
  channel.Close();
  client_dispatcher.Stop();
};
Esempio n. 17
0
void
plugins_init(const char *path)
{
    char *plugins_path;
    lt_dladvise advise;

    if (path && !strcmp(path, "none")) {
        return;
    }

    if (!(plugins_path = path ? xstrdup(path) : xstrdup(ovs_pluginsdir()))) {
        VLOG_ERR("Failed to allocate plugins path");
        return;
    }

    if (lt_dlinit() ||
        lt_dlsetsearchpath(plugins_path) ||
        lt_dladvise_init(&advise)) {
        VLOG_ERR("ltdl initializations: %s", lt_dlerror());
        goto err_init;
    }

    if (!(interface_id = lt_dlinterface_register("ovs-plugin", NULL))) {
        VLOG_ERR("lt_dlinterface_register: %s", lt_dlerror());
        goto err_interface_register;
    }

    if (lt_dladvise_global(&advise) || lt_dladvise_ext (&advise) ||
        lt_dlforeachfile(lt_dlgetsearchpath(), &plugins_open_plugin, &advise)) {
        VLOG_ERR("ltdl setting advise: %s", lt_dlerror());
        goto err_set_advise;
    }

    VLOG_INFO("Successfully initialized all plugins");
    return;

err_set_advise:
    lt_dlinterface_free(interface_id);

err_interface_register:
    if (lt_dladvise_destroy(&advise)) {
        VLOG_ERR("destroying ltdl advise%s", lt_dlerror());
        return;
    }

err_init:
    free(plugins_path);
}
Esempio n. 18
0
 bool HandlePacket(const MessageHeader &header,
                   Buffer* buffer) {
   if (header.opcode != CMSG_ECHO) {
     VLOG_ERROR() << "opcode error: " << header.opcode;
     return false;
   }
   echo::EchoRequest request;
   if (!buffer->DeserializeToMessage(&request, header.length)) {
     VLOG_ERROR() << "DeserializeToMessage error: " << header.length;
     return false;
   }
   VLOG_INFO() << "request: " << request.message();
   echo::EchoResponse response;
   response.set_response(request.message());
   connection_->SendPacket(SMSG_ECHO, &response);
   return true;
 }
Esempio n. 19
0
/* Retrieves the OVN Southbound remote location from the
 * "external-ids:ovn-remote" key in 'ovs_idl' and returns a copy of it.
 *
 * XXX ovn-controller does not support this changing mid-run, but that should
 * be addressed later. */
static char *
get_ovnsb_remote(struct ovsdb_idl *ovs_idl)
{
    while (1) {
        ovsdb_idl_run(ovs_idl);

        const struct ovsrec_open_vswitch *cfg
            = ovsrec_open_vswitch_first(ovs_idl);
        if (cfg) {
            const char *remote = smap_get(&cfg->external_ids, "ovn-remote");
            if (remote) {
                return xstrdup(remote);
            }
        }

        VLOG_INFO("OVN OVSDB remote not specified.  Waiting...");
        ovsdb_idl_wait(ovs_idl);
        poll_block();
    }
}
Esempio n. 20
0
/* Creates and returns a new learning switch whose configuration is given by
 * 'cfg'.
 *
 * 'rconn' is used to send out an OpenFlow features request. */
struct lswitch *
lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg)
{
    struct lswitch *sw;

    sw = xzalloc(sizeof *sw);
    sw->rconn = rconn;
    sw->state = S_CONNECTING;
    sw->max_idle = cfg->max_idle;
    sw->datapath_id = 0;

    sw->default_flows = cfg->default_flows;
    sw->n_default_flows = cfg->n_default_flows;
    sw->usable_protocols = cfg->usable_protocols;
    sw->queued = rconn_packet_counter_create();

    VLOG_INFO("new lswitch in");

    return sw;
}
Esempio n. 21
0
 bool HandlePacket(const MessageHeader &header,
                   Buffer* buffer) {
   if (header.opcode != SMSG_ECHO) {
     VLOG_ERROR() << "opcode error: " << header.opcode;
     return false;
   }
   echo::EchoResponse response;
   if (!buffer->DeserializeToMessage(&response, header.length)) {
     VLOG_ERROR() << "DeserializeToMessage error: " << header.opcode;
     monitor_->Notify();
     return false;
   }
   ++kCount;
   VLOG_INFO() << "response: " << response.response()
     << ", count: " << kCount;
   if (kCount == kMaxConnection) {
     monitor_->Notify();
   }
   return true;
 }
Esempio n. 22
0
static int
create_link_to_desc_files(char *manufacturer, char *product_name)
{
    char        hw_desc_dir[1024];
    int         rc = 0;
    struct stat sbuf;
    extern char *g_hw_desc_dir;

    snprintf(hw_desc_dir, sizeof(hw_desc_dir), "%s/%s/%s",
             HWDESC_FILES_PATH, manufacturer, product_name);

    VLOG_INFO("Location to HW descrptor files: %s", hw_desc_dir);

    g_hw_desc_dir = strdup(hw_desc_dir);

    if (stat(hw_desc_dir, &sbuf) != 0) {
        VLOG_ERR("Unable to find hardware description files at %s", hw_desc_dir);
        return -1;
    }

    /* Remove old link if it exists */
    remove(HWDESC_FILE_LINK);

    /* mkdir for the new link */
    rc = mkdir(HWDESC_FILE_LINK_PATH, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
    if (rc == -1 && errno != EEXIST) {
        VLOG_ERR("Failed to create %s, Error %s",
                 HWDESC_FILE_LINK_PATH, ovs_strerror(errno));
        return -1;
    }

    /* Create link to these files */
    if (-1 == symlink(hw_desc_dir, HWDESC_FILE_LINK)) {
        VLOG_ERR("Unable to create  soft link to %s -> %s. Error %s",
                 HWDESC_FILE_LINK, hw_desc_dir, ovs_strerror(errno));
        return -1;
    }

    return 0;

} /* create_link_to_desc_files */
Esempio n. 23
0
/* Enter fail-open mode if we should be in it. */
void
fail_open_run(struct fail_open *fo)
{
    int disconn_secs = connmgr_failure_duration(fo->connmgr);

    /* Enter fail-open mode if 'fo' is not in it but should be.  */
    if (disconn_secs >= trigger_duration(fo)) {
        if (!fail_open_is_active(fo)) {
            VLOG_WARN("Could not connect to controller (or switch failed "
                      "controller's post-connection admission control "
                      "policy) for %d seconds, failing open", disconn_secs);
            fo->last_disconn_secs = disconn_secs;

            /* Flush all OpenFlow and datapath flows.  We will set up our
             * fail-open rule from fail_open_flushed() when
             * ofproto_flush_flows() calls back to us. */
            ofproto_flush_flows(fo->ofproto);
        } else if (disconn_secs > fo->last_disconn_secs + 60) {
            VLOG_INFO("Still in fail-open mode after %d seconds disconnected "
                      "from controller", disconn_secs);
            fo->last_disconn_secs = disconn_secs;
        }
    }

    /* Schedule a bogus packet-in if we're connected and in fail-open. */
    if (fail_open_is_active(fo)) {
        if (connmgr_is_any_controller_connected(fo->connmgr)) {
            bool expired = time_msec() >= fo->next_bogus_packet_in;
            if (expired) {
                send_bogus_packet_ins(fo);
            }
            if (expired || fo->next_bogus_packet_in == LLONG_MAX) {
                fo->next_bogus_packet_in = time_msec() + 2000;
            }
        } else {
            fo->next_bogus_packet_in = LLONG_MAX;
        }
    }

}
Esempio n. 24
0
static int
ssl_connect(struct stream *stream)
{
    struct ssl_stream *sslv = ssl_stream_cast(stream);
    int retval;

    switch (sslv->state) {
    case STATE_TCP_CONNECTING:
        retval = check_connection_completion(sslv->fd);
        if (retval) {
            return retval;
        }
        sslv->state = STATE_SSL_CONNECTING;
        setsockopt_tcp_nodelay(sslv->fd);
        /* Fall through. */

    case STATE_SSL_CONNECTING:
        /* Capture the first few bytes of received data so that we can guess
         * what kind of funny data we've been sent if SSL negotiation fails. */
        if (sslv->n_head <= 0) {
            sslv->n_head = recv(sslv->fd, sslv->head, sizeof sslv->head,
                                MSG_PEEK);
        }

        retval = (sslv->type == CLIENT
                   ? SSL_connect(sslv->ssl) : SSL_accept(sslv->ssl));
        if (retval != 1) {
            int error = SSL_get_error(sslv->ssl, retval);
            if (retval < 0 && ssl_wants_io(error)) {
                return EAGAIN;
            } else {
                int unused;

                interpret_ssl_error((sslv->type == CLIENT ? "SSL_connect"
                                     : "SSL_accept"), retval, error, &unused);
                shutdown(sslv->fd, SHUT_RDWR);
                stream_report_content(sslv->head, sslv->n_head, STREAM_SSL,
                                      &this_module, stream_get_name(stream));
                return EPROTO;
            }
        } else if (bootstrap_ca_cert) {
            return do_ca_cert_bootstrap(stream);
        } else if (verify_peer_cert
                   && ((SSL_get_verify_mode(sslv->ssl)
                       & (SSL_VERIFY_NONE | SSL_VERIFY_PEER))
                       != SSL_VERIFY_PEER)) {
            /* Two or more SSL connections completed at the same time while we
             * were in bootstrap mode.  Only one of these can finish the
             * bootstrap successfully.  The other one(s) must be rejected
             * because they were not verified against the bootstrapped CA
             * certificate.  (Alternatively we could verify them against the CA
             * certificate, but that's more trouble than it's worth.  These
             * connections will succeed the next time they retry, assuming that
             * they have a certificate against the correct CA.) */
            VLOG_INFO("rejecting SSL connection during bootstrap race window");
            return EPROTO;
        } else {
            return 0;
        }
    }

    OVS_NOT_REACHED();
}
Esempio n. 25
0
int get_packet_list(struct ofpbuf *out_packets[], struct ofpbuf * packet, uint32_t flow_id, uint32_t in_port){

    struct tcp_buf * tcp_buf;    
    uint8_t tcp_flags;
    struct tcp_header *tcp;
    uint32_t seq;
    int i, out_packets_count;
    uint32_t seq_work;
    struct ofpbuf * buf_pkt;
    int removed_items;


    // Getting the buffer for the flow, or creating a new one if 
    // not existing
    tcp_buf = get_tcp_buf(flow_id);

    tcp = ofpbuf_l4(packet);
    tcp_flags = TCP_FLAGS(tcp->tcp_ctl);    
    seq = get_tcp_seq(packet);

    out_packets_count = 0;


    if (tcp_flags & TCP_SYN){
        tcp_buf->expected_seqnum = seq+1;
        VLOG_INFO("[SYN packet] sequence: %" PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 "  size: %d",
            seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items);
        out_packets[out_packets_count] = packet;
        out_packets_count++;
    }
    else if(tcp_buf->fin_state){
        delete_tcp_buf(tcp_buf);
        out_packets[out_packets_count] = packet;
        out_packets_count++;
    }
    // Retransmission or packets which come without a SYN or after a FIN
    // Just send out
    else if(tcp_buf->expected_seqnum == -1){
        out_packets[out_packets_count] = packet;
        out_packets_count++;
    }
    // Sending out and checking if the the gap in the reordering buffer has been filled
    else if(seq <= tcp_buf->expected_seqnum){
        VLOG_INFO("[sending in order packet] seq: %"PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d",
            seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items);

        out_packets[out_packets_count] = packet;
        out_packets_count++;
        tcp_buf->consecutive_buffering_events = 0;

        // Increasing sequence only if it matches
        if(seq == tcp_buf->expected_seqnum){
            tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, packet, false);
        }

        // Check if there are packets waiting to be sent
        removed_items = 0;
        for(i=tcp_buf->inserted_items-1;i>= 0;i--){
            seq_work = get_tcp_seq(tcp_buf->buffer[i]);

            if(seq_work <= tcp_buf->expected_seqnum){
                VLOG_INFO("[sending out from buffer] sequence: %" PRIu32 " expected: %" PRIu32 " size: %d",
                    seq_work, tcp_buf->expected_seqnum, tcp_buf->inserted_items - removed_items);
                removed_items++;            
                out_packets[out_packets_count] = tcp_buf->buffer[i];
                out_packets_count++;
                if(seq_work == tcp_buf->expected_seqnum){
                    tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, tcp_buf->buffer[i], false);
                }
            }
        }
        tcp_buf->inserted_items = tcp_buf->inserted_items - removed_items;
    }
    // Buffer not full yet, buffering the packet
    else if(tcp_buf->inserted_items<TCP_BUF_SIZE && tcp_buf->consecutive_buffering_events < CONSECUTIVE_BUFFERING_TREESHOLD){
        VLOG_INFO("[buffering] sequence: %"PRIu32 " expected: %" PRIu32 " in_port: %"PRIu32 " size: %d",
            seq, tcp_buf->expected_seqnum, in_port, tcp_buf->inserted_items);
        buf_pkt = ofpbuf_clone(packet);
        insert_descending_order(tcp_buf, buf_pkt);
    }
    // Buffer full or loss event detecte
    else{
        VLOG_WARN("!! -- Empty Buffer Event -- !!");
        if(tcp_buf->consecutive_buffering_events >= CONSECUTIVE_BUFFERING_TREESHOLD)
            syslog(LOG_INFO, "!! -- Because of an apparent loss -- !!");

        seq_work = get_tcp_seq(tcp_buf->buffer[tcp_buf->inserted_items-1]);

        // If incoming packet has the smallest sequence
        if(seq<seq_work){
            VLOG_INFO("[resetting buffer] sequence: %" PRIu32, seq);
            out_packets[out_packets_count] = packet;
            out_packets_count++;
        }
        // If a packet in the buffer has the smallest sequence
        else{
            VLOG_INFO("[resetting] sequence: %" PRIu32, get_tcp_seq(tcp_buf->buffer[tcp_buf->inserted_items-1]));
            out_packets[out_packets_count] = tcp_buf->buffer[tcp_buf->inserted_items-1];
            out_packets_count++;
            tcp_buf->inserted_items--;
            buf_pkt = ofpbuf_clone(packet);
            insert_descending_order(tcp_buf, buf_pkt);
        }

        // Completely empty the buffer
        for(i=tcp_buf->inserted_items-1;i>= 0;i--){
            seq_work = get_tcp_seq(tcp_buf->buffer[i]);
            VLOG_INFO("resetting %" PRIu32, seq_work);
            get_next_seqnum(tcp_buf, seq_work, tcp_buf->buffer[i], false);
            out_packets[out_packets_count] = tcp_buf->buffer[i];
            out_packets_count++;

            // Adjusting seqnum
            if(i==0){
                tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, seq_work, tcp_buf->buffer[i], false);
            }
        }

        tcp_buf->inserted_items=0;

        if(tcp_buf->consecutive_buffering_events >= CONSECUTIVE_BUFFERING_TREESHOLD){
            tcp_buf->expected_seqnum = get_next_seqnum(tcp_buf, tcp_buf->expected_seqnum, packet, true);
        }
    }

    return out_packets_count;
}
Esempio n. 26
0
/* Returns this chassis's Chassis record, if it is available and is currently
 * amenable to a transaction. */
const struct sbrec_chassis *
chassis_run(struct controller_ctx *ctx, const char *chassis_id,
            const struct ovsrec_bridge *br_int)
{
    if (!ctx->ovnsb_idl_txn) {
        return NULL;
    }

    const struct ovsrec_open_vswitch *cfg;
    const char *encap_type, *encap_ip;
    static bool inited = false;

    cfg = ovsrec_open_vswitch_first(ctx->ovs_idl);
    if (!cfg) {
        VLOG_INFO("No Open_vSwitch row defined.");
        return NULL;
    }

    encap_type = smap_get(&cfg->external_ids, "ovn-encap-type");
    encap_ip = smap_get(&cfg->external_ids, "ovn-encap-ip");
    if (!encap_type || !encap_ip) {
        VLOG_INFO("Need to specify an encap type and ip");
        return NULL;
    }

    char *tokstr = xstrdup(encap_type);
    char *save_ptr = NULL;
    char *token;
    uint32_t req_tunnels = 0;
    for (token = strtok_r(tokstr, ",", &save_ptr); token != NULL;
         token = strtok_r(NULL, ",", &save_ptr)) {
        uint32_t type = get_tunnel_type(token);
        if (!type) {
            VLOG_INFO("Unknown tunnel type: %s", token);
        }
        req_tunnels |= type;
    }
    free(tokstr);

    const char *hostname = smap_get_def(&cfg->external_ids, "hostname", "");
    char hostname_[HOST_NAME_MAX + 1];
    if (!hostname[0]) {
        if (gethostname(hostname_, sizeof hostname_)) {
            hostname_[0] = '\0';
        }
        hostname = hostname_;
    }

    const char *bridge_mappings = get_bridge_mappings(&cfg->external_ids);
    const char *datapath_type =
        br_int && br_int->datapath_type ? br_int->datapath_type : "";

    struct ds iface_types = DS_EMPTY_INITIALIZER;
    ds_put_cstr(&iface_types, "");
    for (int j = 0; j < cfg->n_iface_types; j++) {
        ds_put_format(&iface_types, "%s,", cfg->iface_types[j]);
    }
    ds_chomp(&iface_types, ',');
    const char *iface_types_str = ds_cstr(&iface_types);

    const struct sbrec_chassis *chassis_rec
        = get_chassis(ctx->ovnsb_idl, chassis_id);

    if (chassis_rec) {
        if (strcmp(hostname, chassis_rec->hostname)) {
            sbrec_chassis_set_hostname(chassis_rec, hostname);
        }

        /* Determine new values for Chassis external-ids. */
        const char *chassis_bridge_mappings
            = get_bridge_mappings(&chassis_rec->external_ids);
        const char *chassis_datapath_type
            = smap_get_def(&chassis_rec->external_ids, "datapath-type", "");
        const char *chassis_iface_types
            = smap_get_def(&chassis_rec->external_ids, "iface-types", "");

        /* If any of the external-ids should change, update them. */
        if (strcmp(bridge_mappings, chassis_bridge_mappings) ||
            strcmp(datapath_type, chassis_datapath_type) ||
            strcmp(iface_types_str, chassis_iface_types)) {
            struct smap new_ids;
            smap_clone(&new_ids, &chassis_rec->external_ids);
            smap_replace(&new_ids, "ovn-bridge-mappings", bridge_mappings);
            smap_replace(&new_ids, "datapath-type", datapath_type);
            smap_replace(&new_ids, "iface-types", iface_types_str);
            sbrec_chassis_verify_external_ids(chassis_rec);
            sbrec_chassis_set_external_ids(chassis_rec, &new_ids);
            smap_destroy(&new_ids);
        }

        /* Compare desired tunnels against those currently in the database. */
        uint32_t cur_tunnels = 0;
        bool same = true;
        for (int i = 0; i < chassis_rec->n_encaps; i++) {
            cur_tunnels |= get_tunnel_type(chassis_rec->encaps[i]->type);
            same = same && !strcmp(chassis_rec->encaps[i]->ip, encap_ip);

            same = same && smap_get_bool(&chassis_rec->encaps[i]->options,
                                         "csum", false);
        }
        same = same && req_tunnels == cur_tunnels;

        if (same) {
            /* Nothing changed. */
            inited = true;
            ds_destroy(&iface_types);
            return chassis_rec;
        } else if (!inited) {
            struct ds cur_encaps = DS_EMPTY_INITIALIZER;
            for (int i = 0; i < chassis_rec->n_encaps; i++) {
                ds_put_format(&cur_encaps, "%s,",
                              chassis_rec->encaps[i]->type);
            }
            ds_chomp(&cur_encaps, ',');

            VLOG_WARN("Chassis config changing on startup, make sure "
                      "multiple chassis are not configured : %s/%s->%s/%s",
                      ds_cstr(&cur_encaps),
                      chassis_rec->encaps[0]->ip,
                      encap_type, encap_ip);
            ds_destroy(&cur_encaps);
        }
    }

    ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
                              "ovn-controller: registering chassis '%s'",
                              chassis_id);

    if (!chassis_rec) {
        struct smap ext_ids = SMAP_INITIALIZER(&ext_ids);
        smap_add(&ext_ids, "ovn-bridge-mappings", bridge_mappings);
        smap_add(&ext_ids, "datapath-type", datapath_type);
        smap_add(&ext_ids, "iface-types", iface_types_str);
        chassis_rec = sbrec_chassis_insert(ctx->ovnsb_idl_txn);
        sbrec_chassis_set_name(chassis_rec, chassis_id);
        sbrec_chassis_set_hostname(chassis_rec, hostname);
        sbrec_chassis_set_external_ids(chassis_rec, &ext_ids);
        smap_destroy(&ext_ids);
    }

    ds_destroy(&iface_types);
    int n_encaps = count_1bits(req_tunnels);
    struct sbrec_encap **encaps = xmalloc(n_encaps * sizeof *encaps);
    const struct smap options = SMAP_CONST1(&options, "csum", "true");

    for (int i = 0; i < n_encaps; i++) {
        const char *type = pop_tunnel_name(&req_tunnels);

        encaps[i] = sbrec_encap_insert(ctx->ovnsb_idl_txn);

        sbrec_encap_set_type(encaps[i], type);
        sbrec_encap_set_ip(encaps[i], encap_ip);
        sbrec_encap_set_options(encaps[i], &options);
    }

    sbrec_chassis_set_encaps(chassis_rec, encaps, n_encaps);
    free(encaps);

    inited = true;
    return chassis_rec;
}
Esempio n. 27
0
File: dpdk.c Progetto: shettyg/ovs
static void
dpdk_init__(const struct smap *ovs_other_config)
{
    char **argv = NULL, **argv_to_release = NULL;
    int result;
    int argc, argc_tmp;
    bool auto_determine = true;
    int err = 0;
    cpu_set_t cpuset;
    char *sock_dir_subcomponent;

    if (process_vhost_flags("vhost-sock-dir", xstrdup(ovs_rundir()),
                            NAME_MAX, ovs_other_config,
                            &sock_dir_subcomponent)) {
        struct stat s;
        if (!strstr(sock_dir_subcomponent, "..")) {
            vhost_sock_dir = xasprintf("%s/%s", ovs_rundir(),
                                       sock_dir_subcomponent);

            err = stat(vhost_sock_dir, &s);
            if (err) {
                VLOG_ERR("vhost-user sock directory '%s' does not exist.",
                         vhost_sock_dir);
            }
        } else {
            vhost_sock_dir = xstrdup(ovs_rundir());
            VLOG_ERR("vhost-user sock directory request '%s/%s' has invalid"
                     "characters '..' - using %s instead.",
                     ovs_rundir(), sock_dir_subcomponent, ovs_rundir());
        }
        free(sock_dir_subcomponent);
    } else {
        vhost_sock_dir = sock_dir_subcomponent;
    }

    argv = grow_argv(&argv, 0, 1);
    argc = 1;
    argv[0] = xstrdup(ovs_get_program_name());
    argc_tmp = get_dpdk_args(ovs_other_config, &argv, argc);

    while (argc_tmp != argc) {
        if (!strcmp("-c", argv[argc]) || !strcmp("-l", argv[argc])) {
            auto_determine = false;
            break;
        }
        argc++;
    }
    argc = argc_tmp;

    /**
     * NOTE: This is an unsophisticated mechanism for determining the DPDK
     * lcore for the DPDK Master.
     */
    if (auto_determine) {
        int i;
        /* Get the main thread affinity */
        CPU_ZERO(&cpuset);
        err = pthread_getaffinity_np(pthread_self(), sizeof(cpu_set_t),
                                     &cpuset);
        if (!err) {
            for (i = 0; i < CPU_SETSIZE; i++) {
                if (CPU_ISSET(i, &cpuset)) {
                    argv = grow_argv(&argv, argc, 2);
                    argv[argc++] = xstrdup("-c");
                    argv[argc++] = xasprintf("0x%08llX", (1ULL<<i));
                    i = CPU_SETSIZE;
                }
            }
        } else {
            VLOG_ERR("Thread getaffinity error %d. Using core 0x1", err);
            /* User did not set dpdk-lcore-mask and unable to get current
             * thread affintity - default to core 0x1 */
            argv = grow_argv(&argv, argc, 2);
            argv[argc++] = xstrdup("-c");
            argv[argc++] = xasprintf("0x%X", 1);
        }
    }

    argv = grow_argv(&argv, argc, 1);
    argv[argc] = NULL;

    optind = 1;

    if (VLOG_IS_INFO_ENABLED()) {
        struct ds eal_args;
        int opt;
        ds_init(&eal_args);
        ds_put_cstr(&eal_args, "EAL ARGS:");
        for (opt = 0; opt < argc; ++opt) {
            ds_put_cstr(&eal_args, " ");
            ds_put_cstr(&eal_args, argv[opt]);
        }
        VLOG_INFO("%s", ds_cstr_ro(&eal_args));
        ds_destroy(&eal_args);
    }

    argv_to_release = grow_argv(&argv_to_release, 0, argc);
    for (argc_tmp = 0; argc_tmp < argc; ++argc_tmp) {
        argv_to_release[argc_tmp] = argv[argc_tmp];
    }

    /* Make sure things are initialized ... */
    result = rte_eal_init(argc, argv);
    if (result < 0) {
        ovs_abort(result, "Cannot init EAL");
    }
    argv_release(argv, argv_to_release, argc);

    /* Set the main thread affinity back to pre rte_eal_init() value */
    if (auto_determine && !err) {
        err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t),
                                     &cpuset);
        if (err) {
            VLOG_ERR("Thread setaffinity error %d", err);
        }
    }

    rte_memzone_dump(stdout);

    /* We are called from the main thread here */
    RTE_PER_LCORE(_lcore_id) = NON_PMD_CORE_ID;

#ifdef DPDK_PDUMP
    VLOG_INFO("DPDK pdump packet capture enabled");
    err = rte_pdump_init(ovs_rundir());
    if (err) {
        VLOG_INFO("Error initialising DPDK pdump");
        rte_pdump_uninit();
    } else {
        char *server_socket_path;

        server_socket_path = xasprintf("%s/%s", ovs_rundir(),
                                       "pdump_server_socket");
        fatal_signal_add_file_to_unlink(server_socket_path);
        free(server_socket_path);
    }
#endif

    /* Finally, register the dpdk classes */
    netdev_dpdk_register();
}
Esempio n. 28
0
/**
 * receive mcast msg, parse and store it.
 * @param group multicast group
 * @param port multicast port
 */
void *mc_recv(struct mc_recv_arg* arg)
{
    int sock_id;
    struct sockaddr_in addr, sender;
    struct ip_mreq ipmr;
    socklen_t len;
    int ret=0;
    int count=0;
    struct mcast_msg *msg = malloc(sizeof(struct mcast_msg));

    /* Step 1: open a socket, and bind */
    if ((sock_id = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket error");
        return NULL;
    }

    memset((void*)&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(arg->port);

    if (bind(sock_id, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind error");
        return NULL;
    }

    /* Step 2: fill in a struct ip_mreq */
    memset((void*)&ipmr, 0, sizeof(ipmr));
    ipmr.imr_multiaddr.s_addr = arg->group_ip; /* multicast group ip */
    ipmr.imr_interface.s_addr = htonl(INADDR_ANY);

    /* Step 3: call setsockopt with IP_ADD_MEMBERSHIP to support receiving multicast */
    if (setsockopt(sock_id, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipmr, sizeof(ipmr)) < 0) {
        perror("setsockopt:IP_ADD_MEMBERSHIP");
        return NULL;
    }

    /* Step 4: call recvfrom to receive multicast packets */
    len = sizeof(sender);

    while (!*arg->stop) {
        ret = recvfrom(sock_id, msg, sizeof(struct mcast_msg),0,(struct sockaddr *)&sender,&len);
        if (ret < 0) {
            perror("recvfrom error");
            continue;
        }
        //VLOG_INFO("[%d] Receive mcast msg from %s:%d gid=%u, bf_id=0x%x, local_id=0x%x.\n", count, inet_ntoa(sender.sin_addr.s_addr), ntohs(sender.sin_port),msg->gid,msg->bf.bf_id,msg->s.entry[0].src_sw_id);

        unsigned int gid = 0;
        FILE* f_gid = fopen("/tmp/lc_gid.dat","r");
        if(f_gid != NULL) {
            fscanf(f_gid,"%u",&gid);
            fclose(f_gid);
        } else {
            gid = arg->gdt->gid;
        }
        if (msg->gid != gid) {
            VLOG_WARN("WARNING: group %u received mcast msg from other group %u\n",gid,msg->gid);
        }
        if (msg->bf.bf_id == arg->local_id){ //from local switch, should ignore
            continue;
        }

        pthread_mutex_lock (&mutex);
        ret = bf_gdt_update_filter(arg->gdt,&msg->bf); //try to update remote bf into ovsd's bf-gdt
        pthread_mutex_unlock (&mutex);
        if(ret > 0) {//sth changed in gdt with msg
            if (ret == 1)
                VLOG_INFO("[MCAST] Received changed bf:gid=%u,id=0x%x,len=%u, will update dp.",msg->gid,msg->bf.bf_id,msg->bf.len);
            else if (ret == 2)
                VLOG_INFO("[MCAST] Received new bf:gid=%u,id=0x%x,len=%u, will update dp.",msg->gid,msg->bf.bf_id,msg->bf.len);
            msg->bf.port_no = LC_BF_REMOTE_PORT; //change default port for remote pkts
            bridge_update_bf_gdt_to_dp(arg->br, &msg->bf);
        }
        if(arg->is_DDCM) { //update the local stat and report to controller via state link.
            FILE* f_stat = fopen("/tmp/lc_stat.dat","a");
            if(f_stat != NULL) {
                int i = 0;
                for (i=0;i<msg->s.num;i++) {
                fprintf(f_stat,"%u %u %lu\n",msg->s.entry[i].src_sw_id,msg->s.entry[i].dst_sw_id,msg->s.entry[i].bytes);
                }
                fclose(f_stat);
            } else {
                continue;
            }
        }
        count ++;
    }

    /* Step 5: call setsockopt with IP_DROP_MEMBERSHIP to drop from multicast */
    if (setsockopt(sock_id, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipmr, sizeof(ipmr)) < 0) {
        perror("setsockopt:IP_DROP_MEMBERSHIP");
        return NULL;
    }

    /* Step 6: close the socket */
    close(sock_id);
    if (msg) free(msg);
    return NULL;
}
Esempio n. 29
0
static void
monitor_daemon(pid_t daemon_pid)
{
    /* XXX Should log daemon's stderr output at startup time. */
    time_t last_restart;
    char *status_msg;
    int crashes;

    set_subprogram_name("monitor");
    status_msg = xstrdup("healthy");
    last_restart = TIME_MIN;
    crashes = 0;
    for (;;) {
        int retval;
        int status;

        proctitle_set("monitoring pid %lu (%s)",
                      (unsigned long int) daemon_pid, status_msg);

        do {
            retval = waitpid(daemon_pid, &status, 0);
        } while (retval == -1 && errno == EINTR);

        if (retval == -1) {
            VLOG_FATAL("waitpid failed (%s)", ovs_strerror(errno));
        } else if (retval == daemon_pid) {
            char *s = process_status_msg(status);
            if (should_restart(status)) {
                free(status_msg);
                status_msg = xasprintf("%d crashes: pid %lu died, %s",
                                       ++crashes,
                                       (unsigned long int) daemon_pid, s);
                free(s);

                if (WCOREDUMP(status)) {
                    /* Disable further core dumps to save disk space. */
                    struct rlimit r;

                    r.rlim_cur = 0;
                    r.rlim_max = 0;
                    if (setrlimit(RLIMIT_CORE, &r) == -1) {
                        VLOG_WARN("failed to disable core dumps: %s",
                                  ovs_strerror(errno));
                    }
                }

                /* Throttle restarts to no more than once every 10 seconds. */
                if (time(NULL) < last_restart + 10) {
                    VLOG_WARN("%s, waiting until 10 seconds since last "
                              "restart", status_msg);
                    for (;;) {
                        time_t now = time(NULL);
                        time_t wakeup = last_restart + 10;
                        if (now >= wakeup) {
                            break;
                        }
                        xsleep(wakeup - now);
                    }
                }
                last_restart = time(NULL);

                VLOG_ERR("%s, restarting", status_msg);
                daemon_pid = fork_and_wait_for_startup(&daemonize_fd);
                if (!daemon_pid) {
                    break;
                }
            } else {
                VLOG_INFO("pid %lu died, %s, exiting",
                          (unsigned long int) daemon_pid, s);
                free(s);
                exit(0);
            }
        }
    }
    free(status_msg);

    /* Running in new daemon process. */
    proctitle_restore();
    set_subprogram_name("");
}
Esempio n. 30
0
static int
do_ca_cert_bootstrap(struct stream *stream)
{
    struct ssl_stream *sslv = ssl_stream_cast(stream);
    STACK_OF(X509) *chain;
    X509 *cert;
    FILE *file;
    int error;
    int fd;

    chain = SSL_get_peer_cert_chain(sslv->ssl);
    if (!chain || !sk_X509_num(chain)) {
        VLOG_ERR("could not bootstrap CA cert: no certificate presented by "
                 "peer");
        return EPROTO;
    }
    cert = sk_X509_value(chain, sk_X509_num(chain) - 1);

    /* Check that 'cert' is self-signed.  Otherwise it is not a CA
     * certificate and we should not attempt to use it as one. */
    error = X509_check_issued(cert, cert);
    if (error) {
        VLOG_ERR("could not bootstrap CA cert: obtained certificate is "
                 "not self-signed (%s)",
                 X509_verify_cert_error_string(error));
        if (sk_X509_num(chain) < 2) {
            VLOG_ERR("only one certificate was received, so probably the peer "
                     "is not configured to send its CA certificate");
        }
        return EPROTO;
    }

    fd = open(ca_cert.file_name, O_CREAT | O_EXCL | O_WRONLY, 0444);
    if (fd < 0) {
        if (errno == EEXIST) {
            VLOG_INFO_RL(&rl, "reading CA cert %s created by another process",
                         ca_cert.file_name);
            stream_ssl_set_ca_cert_file__(ca_cert.file_name, true, true);
            return EPROTO;
        } else {
            VLOG_ERR("could not bootstrap CA cert: creating %s failed: %s",
                     ca_cert.file_name, ovs_strerror(errno));
            return errno;
        }
    }

    file = fdopen(fd, "w");
    if (!file) {
        error = errno;
        VLOG_ERR("could not bootstrap CA cert: fdopen failed: %s",
                 ovs_strerror(error));
        unlink(ca_cert.file_name);
        return error;
    }

    if (!PEM_write_X509(file, cert)) {
        VLOG_ERR("could not bootstrap CA cert: PEM_write_X509 to %s failed: "
                 "%s", ca_cert.file_name,
                 ERR_error_string(ERR_get_error(), NULL));
        fclose(file);
        unlink(ca_cert.file_name);
        return EIO;
    }

    if (fclose(file)) {
        error = errno;
        VLOG_ERR("could not bootstrap CA cert: writing %s failed: %s",
                 ca_cert.file_name, ovs_strerror(error));
        unlink(ca_cert.file_name);
        return error;
    }

    VLOG_INFO("successfully bootstrapped CA cert to %s", ca_cert.file_name);
    log_ca_cert(ca_cert.file_name, cert);
    bootstrap_ca_cert = false;
    ca_cert.read = true;

    /* SSL_CTX_add_client_CA makes a copy of cert's relevant data. */
    SSL_CTX_add_client_CA(ctx, cert);

    SSL_CTX_set_cert_store(ctx, X509_STORE_new());
    if (SSL_CTX_load_verify_locations(ctx, ca_cert.file_name, NULL) != 1) {
        VLOG_ERR("SSL_CTX_load_verify_locations: %s",
                 ERR_error_string(ERR_get_error(), NULL));
        return EPROTO;
    }
    VLOG_INFO("killing successful connection to retry using CA cert");
    return EPROTO;
}