*
* 'ofproto_mutex' must be held whenever an ofconn is created or destroyed or,
* more or less equivalently, whenever an ofconn is added to or removed from a
- * connmgr. 'ofproto_mutex' doesn't protect the data inside the ofconn. */
+ * connmgr. 'ofproto_mutex' doesn't protect the data inside the ofconn, except
+ * as specifically noted below. */
struct ofconn {
/* Configuration that persists from one connection to the next. */
uint32_t master_async_config[OAM_N_TYPES]; /* master, other */
uint32_t slave_async_config[OAM_N_TYPES]; /* slave */
- /* Flow monitors. */
- struct hmap monitors; /* Contains "struct ofmonitor"s. */
- struct list updates; /* List of "struct ofpbuf"s. */
- bool sent_abbrev_update; /* Does 'updates' contain NXFME_ABBREV? */
- struct rconn_packet_counter *monitor_counter;
- uint64_t monitor_paused;
+/* Flow monitors (e.g. NXST_FLOW_MONITOR). */
+
+ /* Configuration. Contains "struct ofmonitor"s. */
+ struct hmap monitors OVS_GUARDED_BY(ofproto_mutex);
+
+ /* Flow control.
+ *
+ * When too many flow monitor notifications back up in the transmit buffer,
+ * we pause the transmission of further notifications. These members track
+ * the flow control state.
+ *
+ * When notifications are flowing, 'monitor_paused' is 0. When
+ * notifications are paused, 'monitor_paused' is the value of
+ * 'monitor_seqno' at the point we paused.
+ *
+ * 'monitor_counter' counts the OpenFlow messages and bytes currently in
+ * flight. This value growing too large triggers pausing. */
+ uint64_t monitor_paused OVS_GUARDED_BY(ofproto_mutex);
+ struct rconn_packet_counter *monitor_counter OVS_GUARDED_BY(ofproto_mutex);
+
+ /* State of monitors for a single ongoing flow_mod.
+ *
+ * 'updates' is a list of "struct ofpbuf"s that contain
+ * NXST_FLOW_MONITOR_REPLY messages representing the changes made by the
+ * current flow_mod.
+ *
+ * When 'updates' is nonempty, 'sent_abbrev_update' is true if 'updates'
+ * 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);
};
static struct ofconn *ofconn_create(struct connmgr *, struct rconn *,
\f
/* Sending asynchronous messages. */
-static void schedule_packet_in(struct ofconn *, struct ofputil_packet_in);
+static void schedule_packet_in(struct ofconn *, struct ofproto_packet_in);
/* Sends an OFPT_PORT_STATUS message with 'opp' and 'reason' to appropriate
* controllers managed by 'mgr'. */
* The caller doesn't need to fill in pin->buffer_id or pin->total_len. */
void
connmgr_send_packet_in(struct connmgr *mgr,
- const struct ofputil_packet_in *pin)
+ const struct ofproto_packet_in *pin)
{
struct ofconn *ofconn;
LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
- if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->reason)
+ if (ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, pin->up.reason)
&& ofconn->controller_id == pin->controller_id) {
schedule_packet_in(ofconn, *pin);
}
/* 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 ofputil_packet_in pin)
+schedule_packet_in(struct ofconn *ofconn, struct ofproto_packet_in pin)
{
struct connmgr *mgr = ofconn->connmgr;
+ uint16_t controller_max_len;
- pin.total_len = pin.packet_len;
+ pin.up.total_len = pin.up.packet_len;
- /* Get OpenFlow buffer_id. */
- if (pin.reason == OFPR_ACTION) {
- pin.buffer_id = UINT32_MAX;
- } else if (mgr->fail_open && fail_open_is_active(mgr->fail_open)) {
- pin.buffer_id = pktbuf_get_null();
- } else if (!ofconn->pktbuf) {
- pin.buffer_id = UINT32_MAX;
+ if (pin.up.reason == OFPR_ACTION) {
+ controller_max_len = pin.send_len; /* max_len */
} else {
- pin.buffer_id = pktbuf_save(ofconn->pktbuf, pin.packet, pin.packet_len,
- pin.fmd.in_port);
+ controller_max_len = ofconn->miss_send_len;
}
- /* Figure out how much of the packet to send. */
- if (pin.reason == OFPR_NO_MATCH) {
- pin.send_len = pin.packet_len;
+ /* Get OpenFlow buffer_id.
+ * For OpenFlow 1.2+, OFPCML_NO_BUFFER (== UINT16_MAX) specifies
+ * unbuffered. This behaviour doesn't violate prior versions, too. */
+ if (controller_max_len == UINT16_MAX) {
+ pin.up.buffer_id = UINT32_MAX;
+ } else if (mgr->fail_open && fail_open_is_active(mgr->fail_open)) {
+ pin.up.buffer_id = pktbuf_get_null();
+ } else if (!ofconn->pktbuf) {
+ pin.up.buffer_id = UINT32_MAX;
} else {
- /* Caller should have initialized 'send_len' to 'max_len' specified in
- * output action. */
+ pin.up.buffer_id = pktbuf_save(ofconn->pktbuf,
+ pin.up.packet, pin.up.packet_len,
+ pin.up.fmd.in_port);
}
- if (pin.buffer_id != UINT32_MAX) {
- pin.send_len = MIN(pin.send_len, ofconn->miss_send_len);
+
+ /* 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
+ && 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()). */
- pinsched_send(ofconn->schedulers[pin.reason == OFPR_NO_MATCH ? 0 : 1],
- pin.fmd.in_port,
- ofputil_encode_packet_in(&pin, ofconn_get_protocol(ofconn),
+ 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);
}
enum ofperr
ofmonitor_create(const struct ofputil_flow_monitor_request *request,
struct ofconn *ofconn, struct ofmonitor **monitorp)
+ OVS_REQUIRES(ofproto_mutex)
{
struct ofmonitor *m;
struct ofmonitor *
ofmonitor_lookup(struct ofconn *ofconn, uint32_t id)
+ OVS_REQUIRES(ofproto_mutex)
{
struct ofmonitor *m;
void
ofmonitor_destroy(struct ofmonitor *m)
+ OVS_REQUIRES(ofproto_mutex)
{
if (m) {
minimatch_destroy(&m->match);
void
ofmonitor_flush(struct connmgr *mgr)
+ OVS_REQUIRES(ofproto_mutex)
{
struct ofconn *ofconn;
static void
ofmonitor_resume(struct ofconn *ofconn)
+ OVS_REQUIRES(ofproto_mutex)
{
struct rule_collection rules;
struct ofpbuf *resumed;
ofconn->monitor_paused = 0;
}
+static bool
+ofmonitor_may_resume(const struct ofconn *ofconn)
+ OVS_REQUIRES(ofproto_mutex)
+{
+ return (ofconn->monitor_paused != 0
+ && !rconn_packet_counter_n_packets(ofconn->monitor_counter));
+}
+
static void
ofmonitor_run(struct connmgr *mgr)
{
struct ofconn *ofconn;
+ ovs_mutex_lock(&ofproto_mutex);
LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
- if (ofconn->monitor_paused
- && !rconn_packet_counter_n_packets(ofconn->monitor_counter)) {
+ if (ofmonitor_may_resume(ofconn)) {
COVERAGE_INC(ofmonitor_resume);
ofmonitor_resume(ofconn);
}
}
+ ovs_mutex_unlock(&ofproto_mutex);
}
static void
{
struct ofconn *ofconn;
+ ovs_mutex_lock(&ofproto_mutex);
LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
- if (ofconn->monitor_paused
- && !rconn_packet_counter_n_packets(ofconn->monitor_counter)) {
+ if (ofmonitor_may_resume(ofconn)) {
poll_immediate_wake();
}
}
+ ovs_mutex_unlock(&ofproto_mutex);
}