/*
- * 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.
#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. */
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);
}
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_*.
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
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
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;
* '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. */
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;
+ 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
}
}
+/* 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
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,