X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=ofproto%2Fconnmgr.c;h=cc947f0d0e44106e5ee6855b09b33da821c3cc7b;hb=95022b47358676771e7b8050542fd4b2edfe18b9;hp=495364fe45ce4634c17f5a1ea8b3ccceb8b1fe1e;hpb=1f42be1c6696df46b46dade5d73470f395426a9c;p=cascardo%2Fovs.git diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c index 495364fe4..cc947f0d0 100644 --- a/ofproto/connmgr.c +++ b/ofproto/connmgr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -90,12 +90,11 @@ struct ofconn { #define OFCONN_REPLY_MAX 100 struct rconn_packet_counter *reply_counter; - /* Asynchronous message configuration in each possible roles. + /* Asynchronous message configuration in each possible role. * * A 1-bit enables sending an asynchronous message for one possible reason * that the message might be generated, a 0-bit disables it. */ - uint32_t master_async_config[OAM_N_TYPES]; /* master, other */ - uint32_t slave_async_config[OAM_N_TYPES]; /* slave */ + struct ofputil_async_cfg *async_cfg; /* Flow table operation logging. */ int n_add, n_delete, n_modify; /* Number of unreported ops of each kind. */ @@ -417,7 +416,7 @@ connmgr_get_memory_usage(const struct connmgr *mgr, struct simap *usage) struct pinsched_stats stats; pinsched_get_stats(ofconn->schedulers[i], &stats); - packets += stats.n_queued;; + packets += stats.n_queued; } packets += pktbuf_count_packets(ofconn->pktbuf); } @@ -949,19 +948,22 @@ ofconn_set_role(struct ofconn *ofconn, enum ofp12_controller_role role) void ofconn_set_invalid_ttl_to_controller(struct ofconn *ofconn, bool enable) { + struct ofputil_async_cfg ac = ofconn_get_async_config(ofconn); uint32_t bit = 1u << OFPR_INVALID_TTL; if (enable) { - ofconn->master_async_config[OAM_PACKET_IN] |= bit; + ac.master[OAM_PACKET_IN] |= bit; } else { - ofconn->master_async_config[OAM_PACKET_IN] &= ~bit; + ac.master[OAM_PACKET_IN] &= ~bit; } + ofconn_set_async_config(ofconn, &ac); } bool ofconn_get_invalid_ttl_to_controller(struct ofconn *ofconn) { + struct ofputil_async_cfg ac = ofconn_get_async_config(ofconn); uint32_t bit = 1u << OFPR_INVALID_TTL; - return (ofconn->master_async_config[OAM_PACKET_IN] & bit) != 0; + return (ac.master[OAM_PACKET_IN] & bit) != 0; } /* Returns the currently configured protocol for 'ofconn', one of OFPUTIL_P_*. @@ -995,18 +997,6 @@ void ofconn_set_protocol(struct ofconn *ofconn, enum ofputil_protocol protocol) { ofconn->protocol = protocol; - if (!(protocol & OFPUTIL_P_OF14_UP)) { - uint32_t *master = ofconn->master_async_config; - uint32_t *slave = ofconn->slave_async_config; - - /* OFPR_ACTION_SET is not supported before OF1.4 */ - master[OAM_PACKET_IN] &= ~(1u << OFPR_ACTION_SET); - slave [OAM_PACKET_IN] &= ~(1u << OFPR_ACTION_SET); - - /* OFPR_GROUP is not supported before OF1.4 */ - master[OAM_PACKET_IN] &= ~(1u << OFPR_GROUP); - slave [OAM_PACKET_IN] &= ~(1u << OFPR_GROUP); - } } /* Returns the currently configured packet in format for 'ofconn', one of @@ -1054,28 +1044,25 @@ ofconn_set_miss_send_len(struct ofconn *ofconn, int miss_send_len) void ofconn_set_async_config(struct ofconn *ofconn, - const uint32_t master_masks[OAM_N_TYPES], - const uint32_t slave_masks[OAM_N_TYPES]) + const struct ofputil_async_cfg *ac) { - size_t size = sizeof ofconn->master_async_config; - memcpy(ofconn->master_async_config, master_masks, size); - memcpy(ofconn->slave_async_config, slave_masks, size); + if (!ofconn->async_cfg) { + ofconn->async_cfg = xmalloc(sizeof *ofconn->async_cfg); + } + *ofconn->async_cfg = *ac; } -void -ofconn_get_async_config(struct ofconn *ofconn, - uint32_t *master_masks, uint32_t *slave_masks) +struct ofputil_async_cfg +ofconn_get_async_config(const struct ofconn *ofconn) { - size_t size = sizeof ofconn->master_async_config; - - /* Make sure we know the protocol version and the async_config - * masks are properly updated by calling ofconn_get_protocol() */ - if (OFPUTIL_P_NONE == ofconn_get_protocol(ofconn)){ - OVS_NOT_REACHED(); + if (ofconn->async_cfg) { + return *ofconn->async_cfg; } - memcpy(master_masks, ofconn->master_async_config, size); - memcpy(slave_masks, ofconn->slave_async_config, size); + int version = rconn_get_version(ofconn->rconn); + return (version < 0 || !ofconn->enable_async_msgs + ? OFPUTIL_ASYNC_CFG_INIT + : ofputil_async_cfg_default(version)); } /* Sends 'msg' on 'ofconn', accounting it as a reply. (If there is a @@ -1288,36 +1275,8 @@ ofconn_flush(struct ofconn *ofconn) rconn_packet_counter_destroy(ofconn->reply_counter); ofconn->reply_counter = rconn_packet_counter_create(); - if (ofconn->enable_async_msgs) { - uint32_t *master = ofconn->master_async_config; - uint32_t *slave = ofconn->slave_async_config; - - /* "master" and "other" roles get all asynchronous messages by default, - * except that the controller needs to enable nonstandard "packet-in" - * reasons itself. */ - master[OAM_PACKET_IN] = ((1u << OFPR_NO_MATCH) - | (1u << OFPR_ACTION) - | (1u << OFPR_ACTION_SET) - | (1u << OFPR_GROUP)); - master[OAM_PORT_STATUS] = ((1u << OFPPR_ADD) - | (1u << OFPPR_DELETE) - | (1u << OFPPR_MODIFY)); - master[OAM_FLOW_REMOVED] = ((1u << OFPRR_IDLE_TIMEOUT) - | (1u << OFPRR_HARD_TIMEOUT) - | (1u << OFPRR_DELETE)); - - /* "slave" role gets port status updates by default. */ - slave[OAM_PACKET_IN] = 0; - slave[OAM_PORT_STATUS] = ((1u << OFPPR_ADD) - | (1u << OFPPR_DELETE) - | (1u << OFPPR_MODIFY)); - slave[OAM_FLOW_REMOVED] = 0; - } else { - memset(ofconn->master_async_config, 0, - sizeof ofconn->master_async_config); - memset(ofconn->slave_async_config, 0, - sizeof ofconn->slave_async_config); - } + free(ofconn->async_cfg); + ofconn->async_cfg = NULL; ofconn->n_add = ofconn->n_delete = ofconn->n_modify = 0; ofconn->first_op = ofconn->last_op = LLONG_MIN; @@ -1499,19 +1458,12 @@ ofconn_log_flow_mods(struct ofconn *ofconn) * 'ofconn'. */ static bool ofconn_receives_async_msg(const struct ofconn *ofconn, - enum ofconn_async_msg_type type, + enum ofputil_async_msg_type type, unsigned int reason) { - const uint32_t *async_config; - ovs_assert(reason < 32); ovs_assert((unsigned int) type < OAM_N_TYPES); - if (ofconn_get_protocol(ofconn) == OFPUTIL_P_NONE - || !rconn_is_connected(ofconn->rconn)) { - return false; - } - /* Keep the following code in sync with the documentation in the * "Asynchronous Messages" section in DESIGN. */ @@ -1521,41 +1473,11 @@ ofconn_receives_async_msg(const struct ofconn *ofconn, return false; } - async_config = (ofconn->role == OFPCR12_ROLE_SLAVE - ? ofconn->slave_async_config - : ofconn->master_async_config); - if (!(async_config[type] & (1u << reason))) { - 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 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 - && (ofproto_table_get_miss_config(ofconn->connmgr->ofproto, - pin->up.table_id) - == OFPUTIL_TABLE_MISS_DEFAULT)) { - return false; - } - } - return true; + struct ofputil_async_cfg ac = ofconn_get_async_config(ofconn); + uint32_t *masks = (ofconn->role == OFPCR12_ROLE_SLAVE + ? ac.slave + : ac.master); + return (masks[type] & (1u << reason)) != 0; } /* The default "table-miss" behaviour for OpenFlow1.3+ is to drop the @@ -1633,9 +1555,6 @@ ofconn_send(const struct ofconn *ofconn, struct ofpbuf *msg, /* Sending asynchronous messages. */ -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'. For messages caused by a controller * OFPT_PORT_MOD, specify 'source' as the controller connection that sent the @@ -1684,6 +1603,28 @@ connmgr_send_port_status(struct connmgr *mgr, struct ofconn *source, } } +/* Sends an OFPT_REQUESTFORWARD message with 'request' and 'reason' to + * appropriate controllers managed by 'mgr'. For messages caused by a + * controller OFPT_GROUP_MOD and OFPT_METER_MOD, specify 'source' as the + * controller connection that sent the request; otherwise, specify 'source' + * as NULL. */ +void +connmgr_send_requestforward(struct connmgr *mgr, const struct ofconn *source, + const struct ofputil_requestforward *rf) +{ + struct ofconn *ofconn; + + LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { + if (ofconn_receives_async_msg(ofconn, OAM_REQUESTFORWARD, rf->reason) + && rconn_get_version(ofconn->rconn) >= OFP14_VERSION + && ofconn != source) { + enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); + ofconn_send(ofconn, ofputil_encode_requestforward(rf, protocol), + NULL); + } + } +} + /* Sends an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message based on 'fr' to * appropriate controllers managed by 'mgr'. */ void @@ -1707,59 +1648,38 @@ 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) -{ - enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); - - if (pin->miss_type == OFPROTO_PACKET_IN_MISS_FLOW - && pin->up.reason == OFPR_ACTION - && protocol != OFPUTIL_P_NONE - && ofputil_protocol_to_ofp_version(protocol) >= OFP13_VERSION) { - return OFPR_NO_MATCH; - } - - switch (pin->up.reason) { - case OFPR_ACTION_SET: - case OFPR_GROUP: - case OFPR_PACKET_OUT: - if (!(protocol & OFPUTIL_P_OF14_UP)) { - /* Only supported in OF1.4+ */ - return OFPR_ACTION; - } - /* Fall through. */ - case OFPR_NO_MATCH: - case OFPR_ACTION: - case OFPR_INVALID_TTL: - case OFPR_N_REASONS: - default: - return pin->up.reason; - } -} - /* Given 'pin', sends an OFPT_PACKET_IN message to each OpenFlow controller as * necessary according to their individual configurations. * * 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 ofproto_packet_in *pin) +connmgr_send_async_msg(struct connmgr *mgr, + const struct ofproto_async_msg *am) { struct ofconn *ofconn; LIST_FOR_EACH (ofconn, node, &mgr->all_conns) { - enum ofp_packet_in_reason reason = wire_reason(ofconn, pin); - - if (ofconn_wants_packet_in_on_miss(ofconn, pin) - && ofconn_receives_async_msg(ofconn, OAM_PACKET_IN, reason) - && ofconn->controller_id == pin->controller_id) { - schedule_packet_in(ofconn, *pin, reason); + enum ofputil_protocol protocol = ofconn_get_protocol(ofconn); + if (protocol == OFPUTIL_P_NONE || !rconn_is_connected(ofconn->rconn) + || ofconn->controller_id != am->controller_id + || !ofconn_receives_async_msg(ofconn, am->oam, + am->pin.up.reason)) { + continue; } + + struct ofpbuf *msg = ofputil_encode_packet_in( + &am->pin.up, protocol, ofconn->packet_in_format, + am->pin.max_len >= 0 ? am->pin.max_len : ofconn->miss_send_len, + ofconn->pktbuf); + + struct ovs_list txq; + bool is_miss = (am->pin.up.reason == OFPR_NO_MATCH || + am->pin.up.reason == OFPR_EXPLICIT_MISS || + am->pin.up.reason == OFPR_IMPLICIT_MISS); + pinsched_send(ofconn->schedulers[is_miss], + am->pin.up.flow_metadata.flow.in_port.ofp_port, + msg, &txq); + do_send_packet_ins(ofconn, &txq); } } @@ -1778,58 +1698,6 @@ do_send_packet_ins(struct ofconn *ofconn, struct ovs_list *txq) } } } - -/* 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, - enum ofp_packet_in_reason wire_reason) -{ - struct connmgr *mgr = ofconn->connmgr; - uint16_t controller_max_len; - struct ovs_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.send_len; /* max_len */ - } else { - controller_max_len = ofconn->miss_send_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 { - pin.up.buffer_id = pktbuf_save(ofconn->pktbuf, - pin.up.packet, pin.up.packet_len, - pin.up.fmd.in_port); - } - - /* 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. */ - 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), - &txq); - do_send_packet_ins(ofconn, &txq); -} /* Fail-open settings. */ @@ -2015,7 +1883,6 @@ connmgr_flushed(struct connmgr *mgr) ofpbuf_init(&ofpacts, OFPACT_OUTPUT_SIZE); ofpact_put_OUTPUT(&ofpacts)->port = OFPP_NORMAL; - ofpact_pad(&ofpacts); match_init_catchall(&match); ofproto_add_flow(mgr->ofproto, &match, 0, ofpacts.data, @@ -2027,7 +1894,7 @@ connmgr_flushed(struct connmgr *mgr) /* Returns the number of hidden rules created by the in-band and fail-open * implementations in table 0. (Subtracting this count from the number of - * rules in the table 0 classifier, as returned by classifier_count(), yields + * rules in the table 0 classifier, as maintained in struct oftable, yields * the number of flows that OVS should report via OpenFlow for table 0.) */ int connmgr_count_hidden_rules(const struct connmgr *mgr) @@ -2376,3 +2243,10 @@ ofmonitor_wait(struct connmgr *mgr) } ovs_mutex_unlock(&ofproto_mutex); } + +void +ofproto_async_msg_free(struct ofproto_async_msg *am) +{ + free(am->pin.up.packet); + free(am); +}