X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=5f2f6f4c0c2ae60f0efede1d6f0f6492fea1048c;hb=d2ede7bc13478e45c58d31a3fe569785b0622682;hp=0c11289cb02f96b850be9f4caf4c6dcb6532faf3;hpb=76ce9432393df462e2030036021ea60096a734d4;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 0c11289c..5f2f6f4c 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -200,9 +200,11 @@ struct ofconn { struct rconn_packet_counter *reply_counter; /* type == OFCONN_CONTROLLER only. */ + enum nx_role role; /* Role. */ struct hmap_node hmap_node; /* In struct ofproto's "controllers" map. */ struct discovery *discovery; /* Controller discovery object, if enabled. */ struct status_category *ss; /* Switch status category. */ + enum ofproto_band band; /* In-band or out-of-band? */ }; /* We use OFPR_NO_MATCH and OFPR_ACTION as indexes into struct ofconn's @@ -246,11 +248,13 @@ struct ofproto { /* Configuration. */ struct switch_status *switch_status; - struct in_band *in_band; struct fail_open *fail_open; struct netflow *netflow; struct ofproto_sflow *sflow; + /* In-band control. */ + struct in_band *in_band; + long long int next_in_band_update; /* Flow table. */ struct classifier cls; bool need_revalidate; @@ -465,6 +469,9 @@ update_controller(struct ofconn *ofconn, const struct ofproto_controller *c) int probe_interval; int i; + ofconn->band = (is_in_band_controller(c) + ? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND); + rconn_set_max_backoff(ofconn->rconn, c->max_backoff); probe_interval = c->probe_interval ? MAX(c->probe_interval, 5) : 0; @@ -513,17 +520,63 @@ find_controller_by_target(struct ofproto *ofproto, const char *target) return NULL; } +static void +update_in_band_remotes(struct ofproto *ofproto) +{ + const struct ofconn *ofconn; + struct sockaddr_in *addrs; + bool discovery; + size_t n_addrs; + + + addrs = xmalloc(hmap_count(&ofproto->controllers) * sizeof *addrs); + n_addrs = 0; + + /* Add all the remotes. */ + discovery = false; + HMAP_FOR_EACH (ofconn, struct ofconn, hmap_node, &ofproto->controllers) { + struct sockaddr_in *sin = &addrs[n_addrs]; + + sin->sin_addr.s_addr = rconn_get_remote_ip(ofconn->rconn); + if (sin->sin_addr.s_addr) { + sin->sin_port = rconn_get_remote_port(ofconn->rconn); + n_addrs++; + } + if (ofconn->discovery) { + discovery = true; + } + } + + /* Create or update or destroy in-band. + * + * Ordinarily we only enable in-band if there's at least one remote + * address, but discovery needs the in-band rules for DHCP to be installed + * even before we know any remote addresses. */ + if (n_addrs || discovery) { + if (!ofproto->in_band) { + in_band_create(ofproto, ofproto->dpif, ofproto->switch_status, + &ofproto->in_band); + } + in_band_set_remotes(ofproto->in_band, addrs, n_addrs); + ofproto->next_in_band_update = time_msec() + 1000; + } else { + in_band_destroy(ofproto->in_band); + ofproto->in_band = NULL; + } + + /* Clean up. */ + free(addrs); +} + void ofproto_set_controllers(struct ofproto *p, const struct ofproto_controller *controllers, size_t n_controllers) { struct shash new_controllers; - struct rconn **in_band_rconns; enum ofproto_fail_mode fail_mode; struct ofconn *ofconn, *next; bool ss_exists; - size_t n_in_band; size_t i; shash_init(&new_controllers); @@ -536,8 +589,6 @@ ofproto_set_controllers(struct ofproto *p, } } - in_band_rconns = xmalloc(n_controllers * sizeof *in_band_rconns); - n_in_band = 0; fail_mode = OFPROTO_FAIL_STANDALONE; ss_exists = false; HMAP_FOR_EACH_SAFE (ofconn, next, struct ofconn, hmap_node, @@ -549,14 +600,9 @@ ofproto_set_controllers(struct ofproto *p, ofconn_destroy(ofconn); } else { update_controller(ofconn, c); - if (ofconn->ss) { ss_exists = true; } - if (is_in_band_controller(c)) { - in_band_rconns[n_in_band++] = ofconn->rconn; - } - if (c->fail == OFPROTO_FAIL_SECURE) { fail_mode = OFPROTO_FAIL_SECURE; } @@ -564,18 +610,7 @@ ofproto_set_controllers(struct ofproto *p, } shash_destroy(&new_controllers); - if (n_in_band) { - if (!p->in_band) { - in_band_create(p, p->dpif, p->switch_status, &p->in_band); - } - if (p->in_band) { - in_band_set_remotes(p->in_band, in_band_rconns, n_in_band); - } - } else { - in_band_destroy(p->in_band); - p->in_band = NULL; - } - free(in_band_rconns); + update_in_band_remotes(p); if (!hmap_is_empty(&p->controllers) && fail_mode == OFPROTO_FAIL_STANDALONE) { @@ -938,6 +973,9 @@ ofproto_run1(struct ofproto *p) } if (p->in_band) { + if (time_msec() >= p->next_in_band_update) { + update_in_band_remotes(p); + } in_band_run(p->in_band); } @@ -1042,6 +1080,7 @@ ofproto_wait(struct ofproto *p) ofconn_wait(ofconn); } if (p->in_band) { + poll_timer_wait(p->next_in_band_update - time_msec()); in_band_wait(p->in_band); } if (p->fail_open) { @@ -1312,6 +1351,10 @@ send_port_status(struct ofproto *p, const struct ofport *ofport, struct ofp_port_status *ops; struct ofpbuf *b; + if (ofconn->role == NX_ROLE_SLAVE) { + continue; + } + ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &b); ops->reason = reason; ops->desc = ofport->opp; @@ -1467,6 +1510,7 @@ ofconn_create(struct ofproto *p, struct rconn *rconn, enum ofconn_type type) list_push_back(&p->all_conns, &ofconn->node); ofconn->rconn = rconn; ofconn->type = type; + ofconn->role = NX_ROLE_OTHER; ofconn->packet_in_counter = rconn_packet_counter_create (); ofconn->pktbuf = NULL; ofconn->miss_send_len = 0; @@ -2074,7 +2118,7 @@ handle_set_config(struct ofproto *p, struct ofconn *ofconn, } flags = ntohs(osc->flags); - if (ofconn->type == OFCONN_CONTROLLER) { + if (ofconn->type == OFCONN_CONTROLLER && ofconn->role != NX_ROLE_SLAVE) { switch (flags & OFPC_FRAG_MASK) { case OFPC_FRAG_NORMAL: dpif_set_drop_frags(p->dpif, false); @@ -2421,6 +2465,29 @@ xlate_actions(const union ofp_action *in, size_t n_in, return 0; } +/* Checks whether 'ofconn' is a slave controller. If so, returns an OpenFlow + * error message code (composed with ofp_mkerr()) for the caller to propagate + * upward. Otherwise, returns 0. + * + * 'oh' is used to make log messages more informative. */ +static int +reject_slave_controller(struct ofconn *ofconn, const struct ofp_header *oh) +{ + if (ofconn->type == OFCONN_CONTROLLER && ofconn->role == NX_ROLE_SLAVE) { + static struct vlog_rate_limit perm_rl = VLOG_RATE_LIMIT_INIT(1, 5); + char *type_name; + + type_name = ofp_message_type_to_string(oh->type); + VLOG_WARN_RL(&perm_rl, "rejecting %s message from slave controller", + type_name); + free(type_name); + + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); + } else { + return 0; + } +} + static int handle_packet_out(struct ofproto *p, struct ofconn *ofconn, struct ofp_header *oh) @@ -2433,6 +2500,11 @@ handle_packet_out(struct ofproto *p, struct ofconn *ofconn, flow_t flow; int error; + error = reject_slave_controller(ofconn, oh); + if (error) { + return error; + } + error = check_ofp_packet_out(oh, &payload, &n_actions, p->max_ports); if (error) { return error; @@ -2494,12 +2566,17 @@ update_port_config(struct ofproto *p, struct ofport *port, } static int -handle_port_mod(struct ofproto *p, struct ofp_header *oh) +handle_port_mod(struct ofproto *p, struct ofconn *ofconn, + struct ofp_header *oh) { const struct ofp_port_mod *opm; struct ofport *port; int error; + error = reject_slave_controller(ofconn, oh); + if (error) { + return error; + } error = check_ofp_message(oh, OFPT_PORT_MOD, sizeof *opm); if (error) { return error; @@ -3296,6 +3373,10 @@ handle_flow_mod(struct ofproto *p, struct ofconn *ofconn, size_t n_actions; int error; + error = reject_slave_controller(ofconn, &ofm->header); + if (error) { + return error; + } error = check_ofp_message_array(&ofm->header, OFPT_FLOW_MOD, sizeof *ofm, sizeof *ofm->actions, &n_actions); if (error) { @@ -3358,6 +3439,59 @@ handle_tun_id_from_cookie(struct ofproto *p, struct nxt_tun_id_cookie *msg) return 0; } +static int +handle_role_request(struct ofproto *ofproto, + struct ofconn *ofconn, struct nicira_header *msg) +{ + struct nx_role_request *nrr; + struct nx_role_request *reply; + struct ofpbuf *buf; + uint32_t role; + + if (ntohs(msg->header.length) != sizeof *nrr) { + VLOG_WARN_RL(&rl, "received role request of length %zu (expected %zu)", + ntohs(msg->header.length), sizeof *nrr); + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN); + } + nrr = (struct nx_role_request *) msg; + + if (ofconn->type != OFCONN_CONTROLLER) { + VLOG_WARN_RL(&rl, "ignoring role request on non-controller " + "connection"); + return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM); + } + + role = ntohl(nrr->role); + if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER + && role != NX_ROLE_SLAVE) { + VLOG_WARN_RL(&rl, "received request for unknown role %"PRIu32, role); + + /* There's no good error code for this. */ + return ofp_mkerr(OFPET_BAD_REQUEST, -1); + } + + if (role == NX_ROLE_MASTER) { + struct ofconn *other; + + HMAP_FOR_EACH (other, struct ofconn, hmap_node, + &ofproto->controllers) { + if (other->role == NX_ROLE_MASTER) { + other->role = NX_ROLE_SLAVE; + } + } + } + ofconn->role = role; + + reply = make_openflow_xid(sizeof *reply, OFPT_VENDOR, msg->header.xid, + &buf); + reply->nxh.vendor = htonl(NX_VENDOR_ID); + reply->nxh.subtype = htonl(NXT_ROLE_REPLY); + reply->role = htonl(role); + queue_tx(buf, ofconn, ofconn->reply_counter); + + return 0; +} + static int handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) { @@ -3388,6 +3522,9 @@ handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg) case NXT_TUN_ID_FROM_COOKIE: return handle_tun_id_from_cookie(p, msg); + + case NXT_ROLE_REQUEST: + return handle_role_request(p, ofconn, msg); } return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); @@ -3440,7 +3577,7 @@ handle_openflow(struct ofconn *ofconn, struct ofproto *p, break; case OFPT_PORT_MOD: - error = handle_port_mod(p, oh); + error = handle_port_mod(p, ofconn, oh); break; case OFPT_FLOW_MOD: @@ -3658,6 +3795,7 @@ uninstall_idle_flow(struct ofproto *ofproto, struct rule *rule) rule_uninstall(ofproto, rule); } } + static void send_flow_removed(struct ofproto *p, struct rule *rule, long long int now, uint8_t reason) @@ -3674,7 +3812,8 @@ send_flow_removed(struct ofproto *p, struct rule *rule, prev = NULL; LIST_FOR_EACH (ofconn, struct ofconn, node, &p->all_conns) { - if (rule->send_flow_removed && rconn_is_connected(ofconn->rconn)) { + if (rule->send_flow_removed && rconn_is_connected(ofconn->rconn) + && ofconn->role != NX_ROLE_SLAVE) { if (prev) { queue_tx(ofpbuf_clone(buf), prev, prev->reply_counter); } else { @@ -3852,11 +3991,13 @@ send_packet_in(struct ofproto *ofproto, struct ofpbuf *packet) prev = NULL; LIST_FOR_EACH (ofconn, struct ofconn, node, &ofproto->all_conns) { - if (prev) { - pinsched_send(prev->schedulers[msg->type], msg->port, - ofpbuf_clone(packet), do_send_packet_in, prev); + if (ofconn->role != NX_ROLE_SLAVE) { + if (prev) { + pinsched_send(prev->schedulers[msg->type], msg->port, + ofpbuf_clone(packet), do_send_packet_in, prev); + } + prev = ofconn; } - prev = ofconn; } if (prev) { pinsched_send(prev->schedulers[msg->type], msg->port,