X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fconnmgr.c;h=da2593036436898412bde72ed644f9c0e638ef97;hb=9a54394ac99e955cf23d8b45cc75ae08316a50f8;hp=bd6e934f9d6364efbaa41194597027603463add5;hpb=f11c7538ba3d4d9fbaabd66457f1c20e95467b1c;p=sliver-openvswitch.git diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index bd6e934f9..da2593036 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -153,7 +153,7 @@ static void ofconn_set_rate_limit(struct ofconn *, int rate, int burst); static void ofconn_send(const struct ofconn *, struct ofpbuf *, struct rconn_packet_counter *); -static void do_send_packet_in(struct ofpbuf *, void *ofconn_); +static void do_send_packet_ins(struct ofconn *, struct list *txq); /* A listener for incoming OpenFlow "service" connections. */ struct ofservice { @@ -912,17 +912,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); } } } @@ -1301,7 +1317,10 @@ ofconn_run(struct ofconn *ofconn, size_t i; for (i = 0; i < N_SCHEDULERS; i++) { - pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn); + struct list txq; + + pinsched_run(ofconn->schedulers[i], &txq); + do_send_packet_ins(ofconn, &txq); } rconn_run(ofconn->rconn); @@ -1435,7 +1454,8 @@ ofconn_send(const struct ofconn *ofconn, struct ofpbuf *msg, /* Sending asynchronous messages. */ -static void schedule_packet_in(struct ofconn *, struct ofproto_packet_in); +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'. */ @@ -1482,6 +1502,25 @@ connmgr_send_flow_removed(struct connmgr *mgr, } } +/* Normally a send-to-controller action uses reason OFPR_ACTION. However, in + * OpenFlow 1.3 and later, packet_ins generated by a send-to-controller action + * in a "table-miss" flow (one with priority 0 and completely wildcarded) are + * sent as OFPR_NO_MATCH. This function returns the reason that should + * actually be sent on 'ofconn' for 'pin'. */ +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) { + enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); + + if (protocol != OFPUTIL_P_NONE + && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) { + return OFPR_NO_MATCH; + } + } + return pin->up.reason; +} + /* Given 'pin', sends an OFPT_PACKET_IN message to each OpenFlow controller as * necessary according to their individual configurations. * @@ -1493,35 +1532,43 @@ connmgr_send_packet_in(struct connmgr *mgr, struct ofconn *ofconn; LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { - if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->up.reason) + enum ofp_packet_in_reason reason = wire_reason(ofconn, pin); + + if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason) && ofconn->controller_id == pin->controller_id) { - schedule_packet_in(ofconn, *pin); + schedule_packet_in(ofconn, *pin, reason); } } } -/* pinsched callback for sending 'ofp_packet_in' on 'ofconn'. */ static void -do_send_packet_in(struct ofpbuf *ofp_packet_in, void *ofconn_) +do_send_packet_ins(struct ofconn *ofconn, struct list *txq) { - struct ofconn *ofconn = ofconn_; + struct ofpbuf *pin, *next_pin; + + LIST_FOR_EACH_SAFE (pin, next_pin, list_node, txq) { + list_remove(&pin->list_node); - rconn_send_with_limit(ofconn->rconn, ofp_packet_in, - ofconn->packet_in_counter, 100); + rconn_send_with_limit(ofconn->rconn, pin, + ofconn->packet_in_counter, 100); + } } /* Takes 'pin', composes an OpenFlow packet-in message from it, and passes it * to 'ofconn''s packet scheduler for sending. */ static void -schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin) +schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin, + enum ofp_packet_in_reason wire_reason) { struct connmgr *mgr = ofconn->connmgr; uint16_t controller_max_len; + struct list txq; pin.up.total_len = pin.up.packet_len; + pin.up.reason = wire_reason; if (pin.up.reason == OFPR_ACTION) { - controller_max_len = pin.up.send_len; /* max_len */ + controller_max_len = pin.send_len; /* max_len */ } else { controller_max_len = ofconn->miss_send_len; } @@ -1544,21 +1591,19 @@ schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin) /* Figure out how much of the packet to send. * If not buffered, send the entire packet. Otherwise, depending on * the reason of packet-in, send what requested by the controller. */ - if (pin.up.buffer_id == UINT32_MAX) { - pin.up.send_len = pin.up.packet_len; - } else { - pin.up.send_len = MIN(pin.up.packet_len, controller_max_len); + if (pin.up.buffer_id != UINT32_MAX + && controller_max_len < pin.up.packet_len) { + pin.up.packet_len = controller_max_len; } - /* Make OFPT_PACKET_IN and hand over to packet scheduler. It might - * immediately call into do_send_packet_in() or it might buffer it for a - * while (until a later call to pinsched_run()). */ + /* Make OFPT_PACKET_IN and hand over to packet scheduler. */ pinsched_send(ofconn->schedulers[pin.up.reason == OFPR_NO_MATCH ? 0 : 1], pin.up.fmd.in_port, ofputil_encode_packet_in(&pin.up, ofconn_get_protocol(ofconn), ofconn->packet_in_format), - do_send_packet_in, ofconn); + &txq); + do_send_packet_ins(ofconn, &txq); } /* Fail-open settings. */