/*
- * 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.
/* 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++) {
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.
*
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. */
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);
}
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
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);
}
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);
}
ovs_mutex_unlock(&rule->mutex);
if (flags & NXFMF_ACTIONS) {
- fu.ofpacts = rule->actions->ofpacts;
- fu.ofpacts_len = rule->actions->ofpacts_len;
+ 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;