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); }
/* Sends 'b' on 'rc'. Returns 0 if successful, or ENOTCONN if 'rc' is not * currently connected. Takes ownership of 'b'. * * If 'counter' is non-null, then 'counter' will be incremented while the * packet is in flight, then decremented when it has been sent (or discarded * due to disconnection). Because 'b' may be sent (or discarded) before this * function returns, the caller may not be able to observe any change in * 'counter'. * * There is no rconn_send_wait() function: an rconn has a send queue that it * takes care of sending if you call rconn_run(), which will have the side * effect of waking up poll_block(). */ int rconn_send(struct rconn *rc, struct rfpbuf *b) { if (rconn_is_connected(rc)) { try_send(rc, b); return 0; } else { return ENOTCONN; } }
static bool fail_open_local_packet_cb(struct relay *r, void *fail_open_) { struct fail_open_data *fail_open = fail_open_; if (rconn_is_connected(fail_open->remote_rconn) || !fail_open->lswitch) { return false; } else { lswitch_process_packet(fail_open->lswitch, fail_open->local_rconn, r->halves[HALF_LOCAL].rxbuf); rconn_run(fail_open->local_rconn); return true; } }
void rconn_status_cb(struct status_reply *sr, void *rconn_) { struct rconn *rconn = rconn_; time_t now = time_now(); status_reply_put(sr, "name=%s", rconn_get_name(rconn)); status_reply_put(sr, "state=%s", rconn_get_state(rconn)); status_reply_put(sr, "backoff=%d", rconn_get_backoff(rconn)); status_reply_put(sr, "is-connected=%s", rconn_is_connected(rconn) ? "true" : "false"); status_reply_put(sr, "sent-msgs=%u", rconn_packets_sent(rconn)); status_reply_put(sr, "received-msgs=%u", rconn_packets_received(rconn)); status_reply_put(sr, "attempted-connections=%u", rconn_get_attempted_connections(rconn)); status_reply_put(sr, "successful-connections=%u", rconn_get_successful_connections(rconn)); status_reply_put(sr, "last-connection=%ld", (long int) (now - rconn_get_last_connection(rconn))); status_reply_put(sr, "time-connected=%lu", rconn_get_total_time_connected(rconn)); status_reply_put(sr, "state-elapsed=%u", rconn_get_state_elapsed(rconn)); }
/* Takes care of necessary 'sw' activity, except for receiving packets (which * the caller must do). */ void lswitch_run(struct lswitch *sw, struct rconn *rconn) { long long int now = time_msec(); if (sw->ml) { mac_learning_run(sw->ml, NULL); } /* If we're waiting for more replies, keeping waiting for up to 10 s. */ if (sw->last_reply != LLONG_MIN) { if (now - sw->last_reply > 10000) { VLOG_ERR_RL(&rl, "%012llx: No more flow stat replies last 10 s", sw->datapath_id); sw->last_reply = LLONG_MIN; sw->last_query = LLONG_MIN; schedule_query(sw, 0); } else { return; } } /* If we're waiting for any reply at all, keep waiting for up to 10 s. */ if (sw->last_query != LLONG_MIN) { if (now - sw->last_query > 10000) { VLOG_ERR_RL(&rl, "%012llx: No flow stat replies in last 10 s", sw->datapath_id); sw->last_query = LLONG_MIN; schedule_query(sw, 0); } else { return; } } /* If it's time to send another query, do so. */ if (sw->next_query != LLONG_MIN && now >= sw->next_query) { sw->next_query = LLONG_MIN; if (!rconn_is_connected(rconn)) { schedule_query(sw, 1000); } else { struct ofp_stats_request *osr; struct ofp_flow_stats_request *ofsr; struct ofpbuf *b; int error; VLOG_DBG("%012llx: Sending flow stats request to implement STP", sw->datapath_id); sw->last_query = now; sw->query_xid = random_uint32(); sw->n_flows = 0; sw->n_no_recv = 0; sw->n_no_send = 0; osr = make_openflow_xid(sizeof *osr + sizeof *ofsr, OFPT_STATS_REQUEST, sw->query_xid, &b); osr->type = htons(OFPST_FLOW); osr->flags = htons(0); ofsr = (struct ofp_flow_stats_request *) osr->body; ofsr->match.wildcards = htonl(OFPFW_ALL); ofsr->table_id = 0xff; ofsr->out_port = htons(OFPP_NONE); error = rconn_send(rconn, b, NULL); if (error) { VLOG_WARN_RL(&rl, "%012llx: sending flow stats request " "failed: %s", sw->datapath_id, strerror(error)); ofpbuf_delete(b); schedule_query(sw, 1000); } } } }