X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fconnmgr.c;h=75d616cfca805248b984807165734179f323f145;hb=HEAD;hp=c9feae52d7097d1b95720760dda1b572f8993d6b;hpb=b9b0087274759ea3aaa55fc489c2265db0445b82;p=sliver-openvswitch.git diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index c9feae52d..75d616cfc 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,8 @@ #include "vconn.h" #include "vlog.h" +#include "bundles.h" + VLOG_DEFINE_THIS_MODULE(connmgr); static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); @@ -129,6 +131,9 @@ struct ofconn { * contains an update event of type NXFME_ABBREV and false otherwise.. */ struct list updates OVS_GUARDED_BY(ofproto_mutex); bool sent_abbrev_update OVS_GUARDED_BY(ofproto_mutex); + + /* Active bundles. Contains "struct ofp_bundle"s. */ + struct hmap bundles; }; static struct ofconn *ofconn_create(struct connmgr *, struct rconn *, @@ -454,7 +459,7 @@ static void add_controller(struct connmgr *, const char *target, uint8_t dscp, OVS_REQUIRES(ofproto_mutex); static struct ofconn *find_controller_by_target(struct connmgr *, const char *target); -static void update_fail_open(struct connmgr *); +static void update_fail_open(struct connmgr *) OVS_EXCLUDED(ofproto_mutex); static int set_pvconns(struct pvconn ***pvconnsp, size_t *n_pvconnsp, const struct sset *); @@ -637,12 +642,13 @@ connmgr_set_controllers(struct connmgr *mgr, shash_destroy(&new_controllers); + ovs_mutex_unlock(&ofproto_mutex); + update_in_band_remotes(mgr); update_fail_open(mgr); if (had_controllers != connmgr_has_controllers(mgr)) { ofproto_flush_flows(mgr->ofproto); } - ovs_mutex_unlock(&ofproto_mutex); } /* Drops the connections between 'mgr' and all of its primary and secondary @@ -733,17 +739,13 @@ update_in_band_remotes(struct connmgr *mgr) /* Add all the remotes. */ HMAP_FOR_EACH (ofconn, hmap_node, &mgr->controllers) { - struct sockaddr_in *sin = &addrs[n_addrs]; const char *target = rconn_get_target(ofconn->rconn); + struct sockaddr_storage ss; - if (ofconn->band == OFPROTO_OUT_OF_BAND) { - continue; - } - - if (stream_parse_target_with_default_port(target, - OFP_OLD_PORT, - sin)) { - n_addrs++; + if (ofconn->band == OFPROTO_IN_BAND + && stream_parse_target_with_default_port(target, OFP_OLD_PORT, &ss) + && ss.ss_family == AF_INET) { + addrs[n_addrs++] = *(struct sockaddr_in *) &ss; } } for (i = 0; i < mgr->n_extra_remotes; i++) { @@ -770,6 +772,7 @@ update_in_band_remotes(struct connmgr *mgr) static void update_fail_open(struct connmgr *mgr) + OVS_EXCLUDED(ofproto_mutex) { if (connmgr_has_controllers(mgr) && mgr->fail_mode == OFPROTO_FAIL_STANDALONE) { @@ -912,17 +915,33 @@ ofconn_get_role(const struct ofconn *ofconn) return ofconn->role; } +void +ofconn_send_role_status(struct ofconn *ofconn, uint32_t role, uint8_t reason) +{ + struct ofputil_role_status status; + struct ofpbuf *buf; + + status.reason = reason; + status.role = role; + ofconn_get_master_election_id(ofconn, &status.generation_id); + + buf = ofputil_encode_role_status(&status, ofconn_get_protocol(ofconn)); + + ofconn_send(ofconn, buf, NULL); +} + /* Changes 'ofconn''s role to 'role'. If 'role' is OFPCR12_ROLE_MASTER then * any existing master is demoted to a slave. */ void ofconn_set_role(struct ofconn *ofconn, enum ofp12_controller_role role) { - if (role == OFPCR12_ROLE_MASTER) { + if (role != ofconn->role && role == OFPCR12_ROLE_MASTER) { struct ofconn *other; HMAP_FOR_EACH (other, hmap_node, &ofconn->connmgr->controllers) { if (other->role == OFPCR12_ROLE_MASTER) { other->role = OFPCR12_ROLE_SLAVE; + ofconn_send_role_status(other, OFPCR12_ROLE_SLAVE, OFPCRR_MASTER_REQUEST); } } } @@ -1122,6 +1141,13 @@ ofconn_add_opgroup(struct ofconn *ofconn, struct list *ofconn_node) { list_push_back(&ofconn->opgroups, ofconn_node); } + +struct hmap * +ofconn_get_bundles(struct ofconn *ofconn) +{ + return &ofconn->bundles; +} + /* Private ofconn functions. */ @@ -1149,6 +1175,8 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type, hmap_init(&ofconn->monitors); list_init(&ofconn->updates); + hmap_init(&ofconn->bundles); + ofconn_flush(ofconn); return ofconn; @@ -1249,6 +1277,8 @@ ofconn_destroy(struct ofconn *ofconn) hmap_remove(&ofconn->connmgr->controllers, &ofconn->hmap_node); } + ofp_bundle_remove_all(ofconn); + hmap_destroy(&ofconn->monitors); list_remove(&ofconn->node); rconn_destroy(ofconn->rconn); @@ -1396,6 +1426,65 @@ ofconn_receives_async_msg(const struct ofconn *ofconn, return true; } +/* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the + * packet rather than to send the packet to the controller. + * + * This function returns false to indicate the packet should be dropped if + * the controller action was the result of the default table-miss behaviour + * and the controller is using OpenFlow1.3+. + * + * Otherwise true is returned to indicate the packet should be forwarded to + * the controller */ +static bool +ofconn_wants_packet_in_on_miss(struct ofconn *ofconn, + const struct ofproto_packet_in *pin) +{ + if (pin->miss_type == OFPROTO_PACKET_IN_MISS_WITHOUT_FLOW) { + enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); + + if (protocol != OFPUTIL_P_NONE + && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) { + enum ofproto_table_config config; + + config = ofproto_table_get_config(ofconn->connmgr->ofproto, + pin->up.table_id); + if (config == OFPROTO_TABLE_MISS_DEFAULT) { + return false; + } + } + } + return true; +} + +/* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the + * packet rather than to send the packet to the controller. + * + * This function returns false to indicate that a packet_in message + * for a "table-miss" should be sent to at least one controller. + * That is there is at least one controller with controller_id 0 + * which connected using an OpenFlow version earlier than OpenFlow1.3. + * + * False otherwise. + * + * This logic assumes that "table-miss" packet_in messages + * are always sent to controller_id 0. */ +bool +connmgr_wants_packet_in_on_miss(struct connmgr *mgr) +{ + struct ofconn *ofconn; + + LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { + enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); + + if (ofconn->controller_id == 0 && + (protocol == OFPUTIL_P_NONE || + ofputil_protocol_to_ofp_version(protocol) < OFP13_VERSION)) { + return true; + } + } + return false; +} + /* Returns a human-readable name for an OpenFlow connection between 'mgr' and * 'target', suitable for use in log messages for identifying the connection. * @@ -1442,9 +1531,11 @@ static void schedule_packet_in(struct ofconn *, struct ofproto_packet_in, enum ofp_packet_in_reason wire_reason); /* Sends an OFPT_PORT_STATUS message with 'opp' and 'reason' to appropriate - * controllers managed by 'mgr'. */ + * controllers managed by 'mgr'. For messages caused by a controller + * OFPT_PORT_MOD, specify 'source' as the controller connection that sent the + * request; otherwise, specify 'source' as NULL. */ void -connmgr_send_port_status(struct connmgr *mgr, +connmgr_send_port_status(struct connmgr *mgr, struct ofconn *source, const struct ofputil_phy_port *pp, uint8_t reason) { /* XXX Should limit the number of queued port status change messages. */ @@ -1457,6 +1548,30 @@ connmgr_send_port_status(struct connmgr *mgr, if (ofconn_receives_async_msg(ofconn, OAM_PORT_STATUS, reason)) { struct ofpbuf *msg; + /* Before 1.5, OpenFlow specified that OFPT_PORT_MOD should not + * generate OFPT_PORT_STATUS messages. That requirement was a + * relic of how OpenFlow originally supported a single controller, + * so that one could expect the controller to already know the + * changes it had made. + * + * EXT-338 changes OpenFlow 1.5 OFPT_PORT_MOD to send + * OFPT_PORT_STATUS messages to every controller. This is + * obviously more useful in the multi-controller case. We could + * always implement it that way in OVS, but that would risk + * confusing controllers that are intended for single-controller + * use only. (Imagine a controller that generates an OFPT_PORT_MOD + * in response to any OFPT_PORT_STATUS!) + * + * So this compromises: for OpenFlow 1.4 and earlier, it generates + * OFPT_PORT_STATUS for OFPT_PORT_MOD, but not back to the + * originating controller. In a single-controller environment, in + * particular, this means that it will never generate + * OFPT_PORT_STATUS for OFPT_PORT_MOD at all. */ + if (ofconn == source + && rconn_get_version(ofconn->rconn) < OFP15_VERSION) { + continue; + } + msg = ofputil_encode_port_status(&ps, ofconn_get_protocol(ofconn)); ofconn_send(ofconn, msg, NULL); } @@ -1494,7 +1609,8 @@ connmgr_send_flow_removed(struct connmgr *mgr, static enum ofp_packet_in_reason wire_reason(struct ofconn *ofconn, const struct ofproto_packet_in *pin) { - if (pin->generated_by_table_miss && pin->up.reason == OFPR_ACTION) { + if (pin->miss_type == OFPROTO_PACKET_IN_MISS_FLOW + && pin->up.reason == OFPR_ACTION) { enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); if (protocol != OFPUTIL_P_NONE @@ -1518,7 +1634,8 @@ connmgr_send_packet_in(struct connmgr *mgr, LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { enum ofp_packet_in_reason reason = wire_reason(ofconn, pin); - if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason) + if (ofconn_wants_packet_in_on_miss(ofconn, pin) + && ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->up.reason) && ofconn->controller_id == pin->controller_id) { schedule_packet_in(ofconn, *pin, reason); } @@ -1533,8 +1650,13 @@ do_send_packet_ins(struct ofconn *ofconn, struct list *txq) LIST_FOR_EACH_SAFE (pin, next_pin, list_node, txq) { list_remove(&pin->list_node); - rconn_send_with_limit(ofconn->rconn, pin, - ofconn->packet_in_counter, 100); + if (rconn_send_with_limit(ofconn->rconn, pin, + ofconn->packet_in_counter, 100) == EAGAIN) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + + VLOG_INFO_RL(&rl, "%s: dropping packet-in due to queue overflow", + rconn_get_name(ofconn->rconn)); + } } } @@ -1777,7 +1899,8 @@ connmgr_flushed(struct connmgr *mgr) ofpact_pad(&ofpacts); match_init_catchall(&match); - ofproto_add_flow(mgr->ofproto, &match, 0, ofpacts.data, ofpacts.size); + ofproto_add_flow(mgr->ofproto, &match, 0, ofpbuf_data(&ofpacts), + ofpbuf_size(&ofpacts)); ofpbuf_uninit(&ofpacts); } @@ -1949,7 +2072,7 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule, default: case NXFME_ABBREV: - NOT_REACHED(); + OVS_NOT_REACHED(); } LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { @@ -1998,8 +2121,9 @@ ofmonitor_report(struct connmgr *mgr, struct rule *rule, ovs_mutex_unlock(&rule->mutex); if (flags & NXFMF_ACTIONS) { - fu.ofpacts = rule->actions->ofpacts; - fu.ofpacts_len = rule->actions->ofpacts_len; + const struct rule_actions *actions = rule_get_actions(rule); + fu.ofpacts = actions->ofpacts; + fu.ofpacts_len = actions->ofpacts_len; } else { fu.ofpacts = NULL; fu.ofpacts_len = 0;