X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ofproto%2Fofproto.c;h=6c93aea02ac295470cecc766a1d084ec7e746061;hb=55e199190427d962831486b5cec0d1723519a197;hp=0c11289cb02f96b850be9f4caf4c6dcb6532faf3;hpb=76ce9432393df462e2030036021ea60096a734d4;p=openvswitch diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 0c11289c..6c93aea0 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,16 @@ 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; + struct sockaddr_in *extra_in_band_remotes; + size_t n_extra_remotes; + /* Flow table. */ struct classifier cls; bool need_revalidate; @@ -465,6 +472,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 +523,68 @@ 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; + size_t max_addrs, n_addrs; + bool discovery; + size_t i; + + /* Allocate enough memory for as many remotes as we could possibly have. */ + max_addrs = ofproto->n_extra_remotes + hmap_count(&ofproto->controllers); + addrs = xmalloc(max_addrs * 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; + } + } + for (i = 0; i < ofproto->n_extra_remotes; i++) { + addrs[n_addrs++] = ofproto->extra_in_band_remotes[i]; + } + + /* 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 +597,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 +608,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 +618,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) { @@ -607,6 +650,47 @@ ofproto_set_controllers(struct ofproto *p, } } +static bool +any_extras_changed(const struct ofproto *ofproto, + const struct sockaddr_in *extras, size_t n) +{ + size_t i; + + if (n != ofproto->n_extra_remotes) { + return true; + } + + for (i = 0; i < n; i++) { + const struct sockaddr_in *old = &ofproto->extra_in_band_remotes[i]; + const struct sockaddr_in *new = &extras[i]; + + if (old->sin_addr.s_addr != new->sin_addr.s_addr || + old->sin_port != new->sin_port) { + return true; + } + } + + return false; +} + +/* Sets the 'n' TCP port addresses in 'extras' as ones to which 'ofproto''s + * in-band control should guarantee access, in the same way that in-band + * control guarantees access to OpenFlow controllers. */ +void +ofproto_set_extra_in_band_remotes(struct ofproto *ofproto, + const struct sockaddr_in *extras, size_t n) +{ + if (!any_extras_changed(ofproto, extras, n)) { + return; + } + + free(ofproto->extra_in_band_remotes); + ofproto->n_extra_remotes = n; + ofproto->extra_in_band_remotes = xmemdup(extras, n * sizeof *extras); + + update_in_band_remotes(ofproto); +} + void ofproto_set_desc(struct ofproto *p, const char *mfr_desc, const char *hw_desc, @@ -810,6 +894,7 @@ ofproto_destroy(struct ofproto *p) in_band_destroy(p->in_band); p->in_band = NULL; + free(p->extra_in_band_remotes); ofproto_flush_flows(p); classifier_destroy(&p->cls); @@ -938,6 +1023,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 +1130,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 +1401,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 +1560,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 +2168,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 +2515,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 +2550,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 +2616,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; @@ -2633,7 +2760,7 @@ handle_table_stats_request(struct ofproto *p, struct ofconn *ofconn, static void append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn, - struct ofpbuf *msg) + struct ofpbuf **msgp) { struct netdev_stats stats; struct ofp_port_stats *ops; @@ -2643,7 +2770,7 @@ append_port_stat(struct ofport *port, uint16_t port_no, struct ofconn *ofconn, * netdev_get_stats() will log errors. */ netdev_get_stats(port->netdev, &stats); - ops = append_stats_reply(sizeof *ops, ofconn, &msg); + ops = append_stats_reply(sizeof *ops, ofconn, msgp); ops->port_no = htons(odp_port_to_ofp_port(port_no)); memset(ops->pad, 0, sizeof ops->pad); ops->rx_packets = htonll(stats.rx_packets); @@ -2681,11 +2808,11 @@ handle_port_stats_request(struct ofproto *p, struct ofconn *ofconn, port = port_array_get(&p->ports, ofp_port_to_odp_port(ntohs(psr->port_no))); if (port) { - append_port_stat(port, ntohs(psr->port_no), ofconn, msg); + append_port_stat(port, ntohs(psr->port_no), ofconn, &msg); } } else { PORT_ARRAY_FOR_EACH (port, &p->ports, port_no) { - append_port_stat(port, port_no, ofconn, msg); + append_port_stat(port, port_no, ofconn, &msg); } } @@ -3296,6 +3423,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 +3489,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 +3572,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 +3627,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 +3845,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 +3862,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 +4041,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,