void classifierd_wait(void) { if (classifierd_run_timer) { poll_timer_wait_until(time_msec() + CLASSIFIERD_RUN_TIMER_INTERVAL_MSEC); classifierd_run_timer = false; } ovsdb_idl_wait(idl); } /* classifierd_wait */
/* Creates and returns a jsonrpc_session that is initially connected to * 'jsonrpc'. If the connection is dropped, it will not be reconnected. * * On the assumption that such connections are likely to be short-lived * (e.g. from ovs-vsctl), informational logging for them is suppressed. */ struct jsonrpc_session * jsonrpc_session_open_unreliably(struct jsonrpc *jsonrpc, uint8_t dscp) { struct jsonrpc_session *s; s = xmalloc(sizeof *s); s->reconnect = reconnect_create(time_msec()); reconnect_set_quiet(s->reconnect, true); reconnect_set_name(s->reconnect, jsonrpc_get_name(jsonrpc)); reconnect_set_max_tries(s->reconnect, 0); reconnect_connected(s->reconnect, time_msec()); s->dscp = dscp; s->rpc = jsonrpc; s->stream = NULL; s->pstream = NULL; s->seqno = 0; return s; }
static void wait_timeout(long long int started) { long long int now = time_msec(); long long int timeout = 10000 - (now - started); if (timeout <= 0) { poll_immediate_wake(); } else { poll_timer_wait(timeout); } }
bool flow_entry_hard_timeout(struct flow_entry *entry) { bool timeout; timeout = (entry->remove_at != 0) && (time_msec() > entry->remove_at); if (timeout) { flow_entry_remove(entry, OFPRR_HARD_TIMEOUT); } return timeout; }
/* Creates and returns a jsonrpc_session to 'name', which should be a string * acceptable to stream_open() or pstream_open(). * * If 'name' is an active connection method, e.g. "tcp:127.1.2.3", the new * jsonrpc_session connects and reconnects, with back-off, to 'name'. * * If 'name' is a passive connection method, e.g. "ptcp:", the new * jsonrpc_session listens for connections to 'name'. It maintains at most one * connection at any given time. Any new connection causes the previous one * (if any) to be dropped. */ struct jsonrpc_session * jsonrpc_session_open(const char *name) { struct jsonrpc_session *s; s = xmalloc(sizeof *s); s->reconnect = reconnect_create(time_msec()); reconnect_set_name(s->reconnect, name); reconnect_enable(s->reconnect, time_msec()); s->rpc = NULL; s->stream = NULL; s->pstream = NULL; s->seqno = 0; if (!pstream_verify_name(name)) { reconnect_set_passive(s->reconnect, true, time_msec()); } return s; }
/* Add tokens to the bucket based on elapsed time. */ static void refill_bucket(struct rate_limiter *rl) { const struct settings *s = rl->s; long long int now = time_msec(); long long int tokens = (now - rl->last_fill) * s->rate_limit + rl->tokens; if (tokens >= 1000) { rl->last_fill = now; rl->tokens = MIN(tokens, s->burst_limit * 1000); } }
bool flow_entry_idle_timeout(struct flow_entry *entry) { bool timeout; timeout = (entry->stats->idle_timeout != 0) && (time_msec() > entry->last_used + entry->stats->idle_timeout * 1000); if (timeout) { flow_entry_remove(entry, OFPRR_IDLE_TIMEOUT); } return timeout; }
/* Creates a new TCP buffer with key flow_id and returns its pointer */ struct tcp_buf * create_new_tcp_buf(uint32_t flow_id){ struct tcp_buf * tcp_buf; tcp_buffers_count++; tcp_buf = malloc (sizeof (struct tcp_buf)); tcp_buf->flow_id = flow_id; tcp_buf->inserted_items = 0; tcp_buf->consecutive_buffering_events = 0; tcp_buf->expected_seqnum = -1; tcp_buf->timeout = time_msec(); tcp_buf->fin_state = false; return tcp_buf; }
/* Return a well formatted string with a time difference at millisecond resolution */ char * elapsed_time (struct timeval * start, struct timeval * stop) { static char et [64]; time_t elapsed = delta_time_in_milliseconds (stop, start); if (time_day (elapsed)) sprintf (et, "%d days, %02d:%02d:%02d.%03ld", time_day (elapsed), time_hour (elapsed), time_min (elapsed), time_sec (elapsed), time_usec (elapsed)); else if (time_hour (elapsed)) sprintf (et, "%02d:%02d:%02d.%03ld", time_hour (elapsed), time_min (elapsed), time_sec (elapsed), time_usec (elapsed)); else if (time_min (elapsed)) sprintf (et, "%02d:%02d.%03ld", time_min (elapsed), time_sec (elapsed), time_usec (elapsed)); else if (time_sec (elapsed)) sprintf (et, "%d.%03d secs", time_sec (elapsed), time_msec (elapsed)); else sprintf (et, "%3d msecs", time_msec (elapsed)); return et; }
/* 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; } } }
struct flow_entry_bv * flow_entry_bv_create(struct datapath *dp, struct flow_table_bv *table, struct ofl_msg_flow_mod *mod) { struct flow_entry_bv *entry; uint64_t now = time_msec(); entry = xmalloc(sizeof(struct flow_entry_bv)); entry->dp = dp; entry->table = table; entry->stats = xmalloc(sizeof(struct ofl_flow_stats)); entry->stats->table_id = mod->table_id; entry->stats->duration_sec = 0; entry->stats->duration_nsec = 0; entry->stats->priority = mod->priority; entry->stats->idle_timeout = mod->idle_timeout; entry->stats->hard_timeout = mod->hard_timeout; entry->stats->cookie = mod->cookie; entry->no_pkt_count = ((mod->flags & OFPFF_NO_PKT_COUNTS) != 0 ); entry->no_byt_count = ((mod->flags & OFPFF_NO_BYT_COUNTS) != 0 ); if (entry->no_pkt_count) entry->stats->packet_count = 0xffffffffffffffff; else entry->stats->packet_count = 0; if (entry->no_byt_count) entry->stats->byte_count = 0xffffffffffffffff; else entry->stats->byte_count = 0; entry->stats->match = mod->match; entry->stats->instructions_num = mod->instructions_num; entry->stats->instructions = mod->instructions; entry->match = mod->match; /* TODO: MOD MATCH? */ entry->created = now; entry->remove_at = mod->hard_timeout == 0 ? 0 : now + mod->hard_timeout * 1000; entry->last_used = now; entry->send_removed = ((mod->flags & OFPFF_SEND_FLOW_REM) != 0); list_init(&entry->match_node); list_init(&entry->idle_node); list_init(&entry->hard_node); list_init(&entry->group_refs); init_group_refs(entry); list_init(&entry->meter_refs); init_meter_refs(entry); return entry; }
/* Configures the program to die with SIGALRM 'secs' seconds from now, if * 'secs' is nonzero, or disables the feature if 'secs' is zero. */ void time_alarm(unsigned int secs) { long long int now; long long int msecs; assert_single_threaded(); time_init(); now = time_msec(); msecs = secs * 1000LL; deadline = now < LLONG_MAX - msecs ? now + msecs : LLONG_MAX; }
void format_odp_flow_stats(struct ds *ds, const struct odp_flow_stats *s) { ds_put_format(ds, "packets:%llu, bytes:%llu, used:", (unsigned long long int) s->n_packets, (unsigned long long int) s->n_bytes); if (s->used_sec) { long long int used = s->used_sec * 1000 + s->used_nsec / 1000000; ds_put_format(ds, "%.3fs", (time_msec() - used) / 1000.0); } else { ds_put_format(ds, "never"); } }
/* Like poll(), except: * * - On error, returns a negative error code (instead of setting errno). * * - If interrupted by a signal, retries automatically until the original * 'timeout' expires. (Because of this property, this function will * never return -EINTR.) * * - As a side effect, refreshes the current time (like time_refresh()). */ int time_poll(struct pollfd *pollfds, int n_pollfds, int timeout) { long long int start; sigset_t oldsigs; bool blocked; int retval; time_refresh(); start = time_msec(); blocked = false; for (;;) { int time_left; if (timeout > 0) { long long int elapsed = time_msec() - start; time_left = timeout >= elapsed ? timeout - elapsed : 0; } else { time_left = timeout; } retval = poll(pollfds, n_pollfds, time_left); if (retval < 0) { retval = -errno; } if (retval != -EINTR) { break; } if (!blocked && deadline == TIME_MIN) { block_sigalrm(&oldsigs); blocked = true; } time_refresh(); } if (blocked) { unblock_sigalrm(&oldsigs); } return retval; }
void jsonrpc_session_wait(struct jsonrpc_session *s) { if (s->rpc) { jsonrpc_wait(s->rpc); } else if (s->stream) { stream_run_wait(s->stream); stream_connect_wait(s->stream); } if (s->pstream) { pstream_wait(s->pstream); } reconnect_wait(s->reconnect, time_msec()); }
static void jsonrpc_session_connect(struct jsonrpc_session *s) { const char *name = reconnect_get_name(s->reconnect); int error; jsonrpc_session_disconnect(s); if (!reconnect_is_passive(s->reconnect)) { error = jsonrpc_stream_open(name, &s->stream); if (!error) { reconnect_connecting(s->reconnect, time_msec()); } } else { error = s->pstream ? 0 : jsonrpc_pstream_open(name, &s->pstream); if (!error) { reconnect_listening(s->reconnect, time_msec()); } } if (error) { reconnect_connect_failed(s->reconnect, time_msec(), error); } s->seqno++; }
struct group_entry * group_entry_create(struct datapath *dp, struct group_table *table, struct ofl_msg_group_mod *mod) { struct group_entry *entry; size_t i; uint64_t now; now = time_msec(); entry = xmalloc(sizeof(struct group_entry)); entry->dp = dp; entry->table = table; entry->desc = xmalloc(sizeof(struct ofl_group_desc_stats)); entry->desc->type = mod->type; entry->desc->group_id = mod->group_id; entry->desc->buckets_num = mod->buckets_num; entry->desc->buckets = mod->buckets; entry->stats = xmalloc(sizeof(struct ofl_group_stats)); entry->stats->group_id = mod->group_id; entry->stats->ref_count = 0; entry->stats->packet_count = 0; entry->stats->byte_count = 0; entry->stats->counters_num = mod->buckets_num; entry->stats->counters = (struct ofl_bucket_counter **) xmalloc(sizeof(struct ofl_bucket_counter *) * entry->stats->counters_num); entry->stats->duration_sec = 0; entry->stats->duration_nsec = 0; for (i=0; i<entry->stats->counters_num; i++) { entry->stats->counters[i] = (struct ofl_bucket_counter *) xmalloc(sizeof(struct ofl_bucket_counter)); entry->stats->counters[i]->packet_count = 0; entry->stats->counters[i]->byte_count = 0; } switch (mod->type) { case (OFPGT_SELECT): { init_select_group(entry, mod); break; } default: { entry->data = NULL; } } list_init(&entry->flow_refs); return entry; }
struct flow_entry * flow_entry_create(struct datapath *dp, struct flow_table *table, struct ofl_msg_flow_mod *mod) { struct flow_entry *entry; uint64_t now; now = time_msec(); entry = xmalloc(sizeof(struct flow_entry)); entry->dp = dp; entry->table = table; entry->stats = xmalloc(sizeof(struct ofl_flow_stats)); entry->stats->table_id = mod->table_id; entry->stats->duration_sec = 0; entry->stats->duration_nsec = 0; entry->stats->priority = mod->priority; entry->stats->importance = mod->importance; //modified by dingwanfu. entry->stats->idle_timeout = mod->idle_timeout; entry->stats->hard_timeout = mod->hard_timeout; entry->stats->cookie = mod->cookie; entry->stats->packet_count = 0; entry->stats->byte_count = 0; entry->stats->match = mod->match; entry->stats->instructions_num = mod->instructions_num; entry->stats->instructions = mod->instructions; entry->match = mod->match; /* TODO: MOD MATCH? */ entry->created = now; entry->remove_at = mod->hard_timeout == 0 ? 0 : now + mod->hard_timeout * 1000; entry->last_used = now; entry->send_removed = ((mod->flags & OFPFF_SEND_FLOW_REM) != 0); list_init(&entry->match_node); list_init(&entry->idle_node); list_init(&entry->hard_node); list_init(&entry->group_refs); init_group_refs(entry); return entry; }
void rate_limit_start(struct secchan *secchan, const struct settings *s, struct switch_status *ss, struct rconn *remote) { struct rate_limiter *rl; size_t i; rl = xcalloc(1, sizeof *rl); rl->s = s; rl->remote_rconn = remote; for (i = 0; i < ARRAY_SIZE(rl->queues); i++) { queue_init(&rl->queues[i]); } rl->last_fill = time_msec(); rl->tokens = s->rate_limit * 100; switch_status_register_category(ss, "rate-limit", rate_limit_status_cb, rl); add_hook(secchan, &rate_limit_hook_class, rl); }
static void * ct_thread_main(void *aux_) { struct thread_aux *aux = aux_; struct dp_packet_batch *pkt_batch; ovs_be16 dl_type; size_t i; long long now = time_msec(); pkt_batch = prepare_packets(batch_size, change_conn, aux->tid, &dl_type); ovs_barrier_block(&barrier); for (i = 0; i < n_pkts; i += batch_size) { conntrack_execute(ct, pkt_batch, dl_type, false, true, 0, NULL, NULL, 0, 0, NULL, NULL, now); } ovs_barrier_block(&barrier); destroy_packets(pkt_batch); return NULL; }
static void log_poll_interval(long long int last_wakeup) { long long int interval = time_msec() - last_wakeup; if (interval >= 1000 && !is_warped(&monotonic_clock)) { const struct rusage *last_rusage = get_recent_rusage(); struct rusage rusage; getrusage(RUSAGE_SELF, &rusage); VLOG_WARN("Unreasonably long %lldms poll interval" " (%lldms user, %lldms system)", interval, timeval_diff_msec(&rusage.ru_utime, &last_rusage->ru_utime), timeval_diff_msec(&rusage.ru_stime, &last_rusage->ru_stime)); if (rusage.ru_minflt > last_rusage->ru_minflt || rusage.ru_majflt > last_rusage->ru_majflt) { VLOG_WARN("faults: %ld minor, %ld major", rusage.ru_minflt - last_rusage->ru_minflt, rusage.ru_majflt - last_rusage->ru_majflt); } if (rusage.ru_inblock > last_rusage->ru_inblock || rusage.ru_oublock > last_rusage->ru_oublock) { VLOG_WARN("disk: %ld reads, %ld writes", rusage.ru_inblock - last_rusage->ru_inblock, rusage.ru_oublock - last_rusage->ru_oublock); } if (rusage.ru_nvcsw > last_rusage->ru_nvcsw || rusage.ru_nivcsw > last_rusage->ru_nivcsw) { VLOG_WARN("context switches: %ld voluntary, %ld involuntary", rusage.ru_nvcsw - last_rusage->ru_nvcsw, rusage.ru_nivcsw - last_rusage->ru_nivcsw); } coverage_log(); } }
static void pcap_batch_execute_conntrack(struct conntrack *ct_, struct dp_packet_batch *pkt_batch) { struct dp_packet_batch new_batch; ovs_be16 dl_type = htons(0); long long now = time_msec(); dp_packet_batch_init(&new_batch); /* pkt_batch contains packets with different 'dl_type'. We have to * call conntrack_execute() on packets with the same 'dl_type'. */ struct dp_packet *packet; DP_PACKET_BATCH_FOR_EACH (i, packet, pkt_batch) { struct flow flow; /* This also initializes the l3 and l4 pointers. */ flow_extract(packet, &flow); if (dp_packet_batch_is_empty(&new_batch)) { dl_type = flow.dl_type; } if (flow.dl_type != dl_type) { conntrack_execute(ct_, &new_batch, dl_type, false, true, 0, NULL, NULL, 0, 0, NULL, NULL, now); dp_packet_batch_init(&new_batch); } dp_packet_batch_add(&new_batch, packet); } if (!dp_packet_batch_is_empty(&new_batch)) { conntrack_execute(ct_, &new_batch, dl_type, false, true, 0, NULL, NULL, 0, 0, NULL, NULL, now); } }
/* Add tokens to the bucket based on elapsed time. */ void refill_bucket(struct meter_entry *entry) { size_t i; for(i = 0; i < entry->config->meter_bands_num; i++) { long long int now = time_msec(); uint32_t rate; uint32_t burst_size; uint64_t tokens; rate = entry->config->bands[i]->rate * 1000; burst_size = entry->config->bands[i]->burst_size * 1000; tokens = (now - entry->stats->band_stats[i]->last_fill) * rate + entry->stats->band_stats[i]->tokens; entry->stats->band_stats[i]->last_fill = now; if (!(entry->config->flags & OFPMF_BURST)){ if(entry->config->flags & OFPMF_KBPS && tokens >= 1){ entry->stats->band_stats[i]->tokens = MIN(tokens, rate); } else{ if(tokens >= 1000) { entry->stats->band_stats[i]->tokens = MIN(tokens, rate); } } } else { if(entry->config->flags & OFPMF_KBPS && tokens >= 1 ){ entry->stats->band_stats[i]->tokens = MIN(tokens,burst_size); } else { if(tokens >= 1000) { entry->stats->band_stats[i]->tokens = MIN(tokens,burst_size); } } } } }
struct jsonrpc_msg * jsonrpc_session_recv(struct jsonrpc_session *s) { if (s->rpc) { unsigned int received_bytes; struct jsonrpc_msg *msg; received_bytes = jsonrpc_get_received_bytes(s->rpc); jsonrpc_recv(s->rpc, &msg); if (received_bytes != jsonrpc_get_received_bytes(s->rpc)) { /* Data was successfully received. * * Previously we only counted receiving a full message as activity, * but with large messages or a slow connection that policy could * time out the session mid-message. */ reconnect_activity(s->reconnect, time_msec()); } if (msg) { if (msg->type == JSONRPC_REQUEST && !strcmp(msg->method, "echo")) { /* Echo request. Send reply. */ struct jsonrpc_msg *reply; reply = jsonrpc_create_reply(json_clone(msg->params), msg->id); jsonrpc_session_send(s, reply); } else if (msg->type == JSONRPC_REPLY && msg->id && msg->id->type == JSON_STRING && !strcmp(msg->id->u.string, "echo")) { /* It's a reply to our echo request. Suppress it. */ } else { return msg; } jsonrpc_msg_destroy(msg); } } return NULL; }
struct flow_entry * flow_table_lookup(struct flow_table *table, struct packet *pkt) { struct flow_entry *entry; table->stats->lookup_count++; LIST_FOR_EACH(entry, struct flow_entry, match_node, &table->match_entries) { struct ofl_match_header *m; m = entry->match == NULL ? entry->stats->match : entry->match; /* select appropriate handler, based on match type of flow entry. */ switch (m->type) { case (OFPMT_OXM): { if (packet_handle_std_match(pkt->handle_std, (struct ofl_match *)m)) { entry->stats->byte_count += pkt->buffer->size; entry->stats->packet_count++; entry->last_used = time_msec(); table->stats->matched_count++; return entry; } break; break; } default: { VLOG_WARN_RL(LOG_MODULE, &rl, "Trying to process flow entry with unknown match type (%u).", m->type); } } } return NULL; }
void group_entry_update(struct group_entry *entry){ entry->stats->duration_sec = (time_msec() - entry->created) / 1000; entry->stats->duration_nsec = ((time_msec() - entry->created) % 1000) * 1000; }
int main(int argc, char **argv) { int verbose = 0; int count = 5; double rt, min, max, avg; double a = 0.7, b = -0.88, c; armas_x_dense_t A; int ok, opt, i; long k, N = 30000000; int nproc = 1; int avx_test = 0; int fma_test = 0; int testno = 0; while ((opt = getopt(argc, argv, "c:vt:AF")) != -1) { switch (opt) { case 'v': verbose = 1; break; case 't': testno = atoi(optarg); break; case 'c': count = atoi(optarg); break; case 'A': avx_test = 1; break; case 'F': fma_test = 1; break; default: fprintf(stderr, "usage: perfgv [-c count -v] [size]\n"); exit(1); } } if (optind < argc) N = atol(argv[optind]); long seed = (long)time(0); srand48(seed); // C = A*B min = max = avg = 0.0; for (i = 0; i < count; i++) { flush(); if (fma_test) { rt = time_msec(); c = test_gvcomp_fma(a, b, N); rt = time_msec() - rt; } else if (avx_test) { rt = time_msec(); c = test_gvcomp_avx(a, b, N); rt = time_msec() - rt; } else { rt = time_msec(); c = test_gvcomp(a, b, N); rt = time_msec() - rt; } if (i == 0) { min = max = avg = rt; } else { if (rt < min) min = rt; if (rt > max) max = rt; avg += (rt - avg)/(i+1); } if (verbose) printf("%2d: %.4f, %.4f, %.4f msec\n", i, min, avg, max); } int64_t nops = 7*(int64_t)N; if (testno == 0) { nops = N; nops *= 7; } else if (testno == 2) { nops = N*N; nops *= 7; } printf("N: %4ld, %8.4f, %8.4f, %8.4f Gflops\n", N, gflops(max, nops), gflops(avg, nops), gflops(min, nops)); printf("c=%.f\n", c); return 0; }
void jsonrpc_session_run(struct jsonrpc_session *s) { if (s->pstream) { struct stream *stream; int error; error = pstream_accept(s->pstream, &stream); if (!error) { if (s->rpc || s->stream) { VLOG_INFO_RL(&rl, "%s: new connection replacing active connection", reconnect_get_name(s->reconnect)); jsonrpc_session_disconnect(s); } reconnect_connected(s->reconnect, time_msec()); s->rpc = jsonrpc_open(stream); } else if (error != EAGAIN) { reconnect_listen_error(s->reconnect, time_msec(), error); pstream_close(s->pstream); s->pstream = NULL; } } if (s->rpc) { size_t backlog; int error; backlog = jsonrpc_get_backlog(s->rpc); jsonrpc_run(s->rpc); if (jsonrpc_get_backlog(s->rpc) < backlog) { /* Data previously caught in a queue was successfully sent (or * there's an error, which we'll catch below.) * * We don't count data that is successfully sent immediately as * activity, because there's a lot of queuing downstream from us, * which means that we can push a lot of data into a connection * that has stalled and won't ever recover. */ reconnect_activity(s->reconnect, time_msec()); } error = jsonrpc_get_status(s->rpc); if (error) { reconnect_disconnected(s->reconnect, time_msec(), error); jsonrpc_session_disconnect(s); s->last_error = error; } } else if (s->stream) { int error; stream_run(s->stream); error = stream_connect(s->stream); if (!error) { reconnect_connected(s->reconnect, time_msec()); s->rpc = jsonrpc_open(s->stream); s->stream = NULL; } else if (error != EAGAIN) { reconnect_connect_failed(s->reconnect, time_msec(), error); stream_close(s->stream); s->stream = NULL; s->last_error = error; } } switch (reconnect_run(s->reconnect, time_msec())) { case RECONNECT_CONNECT: jsonrpc_session_connect(s); break; case RECONNECT_DISCONNECT: reconnect_disconnected(s->reconnect, time_msec(), 0); jsonrpc_session_disconnect(s); break; case RECONNECT_PROBE: if (s->rpc) { struct json *params; struct jsonrpc_msg *request; params = json_array_create_empty(); request = jsonrpc_create_request("echo", params, NULL); json_destroy(request->id); request->id = json_string_create("echo"); jsonrpc_send(s->rpc, request); } break; } }
/* Forces 's' to drop its connection (if any) and reconnect. */ void jsonrpc_session_force_reconnect(struct jsonrpc_session *s) { reconnect_force_reconnect(s->reconnect, time_msec()); }
/* Populates 'stats' with statistics from 's'. */ void jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *s, struct reconnect_stats *stats) { reconnect_get_stats(s->reconnect, time_msec(), stats); }