- return;
- }
-
- /* Create a new ofport. */
- new_ofport = !error ? make_ofport(&odp_port) : NULL;
-
- /* Eliminate a few pathological cases. */
- if (!old_ofport && !new_ofport) {
- return;
- } else if (old_ofport && new_ofport) {
- /* Most of the 'config' bits are OpenFlow soft state, but
- * OFPPC_PORT_DOWN is maintained by the kernel. So transfer the
- * OpenFlow bits from old_ofport. (make_ofport() only sets
- * OFPPC_PORT_DOWN and leaves the other bits 0.) */
- new_ofport->opp.config |= old_ofport->opp.config & ~OFPPC_PORT_DOWN;
-
- if (ofport_equal(old_ofport, new_ofport)) {
- /* False alarm--no change. */
- ofport_free(new_ofport);
- return;
- }
- }
-
- /* Now deal with the normal cases. */
- if (old_ofport) {
- ofport_remove(p, old_ofport);
- }
- if (new_ofport) {
- ofport_install(p, new_ofport);
- }
- send_port_status(p, new_ofport ? new_ofport : old_ofport,
- (!old_ofport ? OFPPR_ADD
- : !new_ofport ? OFPPR_DELETE
- : OFPPR_MODIFY));
- ofport_free(old_ofport);
-}
-
-static int
-init_ports(struct ofproto *p)
-{
- struct odp_port *ports;
- size_t n_ports;
- size_t i;
- int error;
-
- error = dpif_port_list(p->dpif, &ports, &n_ports);
- if (error) {
- return error;
- }
-
- for (i = 0; i < n_ports; i++) {
- const struct odp_port *odp_port = &ports[i];
- if (!ofport_conflicts(p, odp_port)) {
- struct ofport *ofport = make_ofport(odp_port);
- if (ofport) {
- ofport_install(p, ofport);
- }
- }
- }
- free(ports);
- return 0;
-}
-\f
-static struct ofconn *
-ofconn_create(struct ofproto *p, struct rconn *rconn, enum ofconn_type type)
-{
- struct ofconn *ofconn = xzalloc(sizeof *ofconn);
- ofconn->ofproto = p;
- list_push_back(&p->all_conns, &ofconn->node);
- ofconn->rconn = rconn;
- ofconn->type = type;
- ofconn->flow_format = NXFF_OPENFLOW10;
- ofconn->role = NX_ROLE_OTHER;
- ofconn->packet_in_counter = rconn_packet_counter_create ();
- ofconn->pktbuf = NULL;
- ofconn->miss_send_len = 0;
- ofconn->reply_counter = rconn_packet_counter_create ();
- return ofconn;
-}
-
-static void
-ofconn_destroy(struct ofconn *ofconn)
-{
- if (ofconn->type == OFCONN_PRIMARY) {
- hmap_remove(&ofconn->ofproto->controllers, &ofconn->hmap_node);
- }
- discovery_destroy(ofconn->discovery);
-
- list_remove(&ofconn->node);
- switch_status_unregister(ofconn->ss);
- rconn_destroy(ofconn->rconn);
- rconn_packet_counter_destroy(ofconn->packet_in_counter);
- rconn_packet_counter_destroy(ofconn->reply_counter);
- pktbuf_destroy(ofconn->pktbuf);
- free(ofconn);
-}
-
-static void
-ofconn_run(struct ofconn *ofconn)
-{
- struct ofproto *p = ofconn->ofproto;
- int iteration;
- size_t i;
-
- if (ofconn->discovery) {
- char *controller_name;
- if (rconn_is_connectivity_questionable(ofconn->rconn)) {
- discovery_question_connectivity(ofconn->discovery);
- }
- if (discovery_run(ofconn->discovery, &controller_name)) {
- if (controller_name) {
- char *ofconn_name = ofconn_make_name(p, controller_name);
- rconn_connect(ofconn->rconn, controller_name, ofconn_name);
- free(ofconn_name);
- } else {
- rconn_disconnect(ofconn->rconn);
- }
- }
- }
-
- for (i = 0; i < N_SCHEDULERS; i++) {
- pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn);
- }
-
- rconn_run(ofconn->rconn);
-
- if (rconn_packet_counter_read (ofconn->reply_counter) < OFCONN_REPLY_MAX) {
- /* Limit the number of iterations to prevent other tasks from
- * starving. */
- for (iteration = 0; iteration < 50; iteration++) {
- struct ofpbuf *of_msg = rconn_recv(ofconn->rconn);
- if (!of_msg) {
- break;
- }
- if (p->fail_open) {
- fail_open_maybe_recover(p->fail_open);
- }
- handle_openflow(ofconn, of_msg);
- ofpbuf_delete(of_msg);
- }
- }
-
- if (!ofconn->discovery && !rconn_is_alive(ofconn->rconn)) {
- ofconn_destroy(ofconn);
- }
-}
-
-static void
-ofconn_wait(struct ofconn *ofconn)
-{
- int i;
-
- if (ofconn->discovery) {
- discovery_wait(ofconn->discovery);
- }
- for (i = 0; i < N_SCHEDULERS; i++) {
- pinsched_wait(ofconn->schedulers[i]);
- }
- rconn_run_wait(ofconn->rconn);
- if (rconn_packet_counter_read (ofconn->reply_counter) < OFCONN_REPLY_MAX) {
- rconn_recv_wait(ofconn->rconn);
- } else {
- COVERAGE_INC(ofproto_ofconn_stuck);
- }
-}
-
-/* Returns true if 'ofconn' should receive asynchronous messages. */
-static bool
-ofconn_receives_async_msgs(const struct ofconn *ofconn)
-{
- if (ofconn->type == OFCONN_PRIMARY) {
- /* Primary controllers always get asynchronous messages unless they
- * have configured themselves as "slaves". */
- return ofconn->role != NX_ROLE_SLAVE;
- } else {
- /* Service connections don't get asynchronous messages unless they have
- * explicitly asked for them by setting a nonzero miss send length. */
- return ofconn->miss_send_len > 0;
- }
-}
-
-/* Returns a human-readable name for an OpenFlow connection between 'ofproto'
- * and 'target', suitable for use in log messages for identifying the
- * connection.
- *
- * The name is dynamically allocated. The caller should free it (with free())
- * when it is no longer needed. */
-static char *
-ofconn_make_name(const struct ofproto *ofproto, const char *target)
-{
- return xasprintf("%s<->%s", dpif_base_name(ofproto->dpif), target);
-}