ofproto->sw_desc = xstrdup(DEFAULT_SW_DESC);
ofproto->serial_desc = xstrdup(DEFAULT_SERIAL_DESC);
ofproto->dp_desc = xstrdup(DEFAULT_DP_DESC);
+ ofproto->frag_handling = OFPC_FRAG_NORMAL;
hmap_init(&ofproto->ports);
shash_init(&ofproto->port_by_name);
ofproto->tables = NULL;
}
}
\f
+/* Spanning Tree Protocol (STP) configuration. */
+
+/* Configures STP on 'ofproto' using the settings defined in 's'. If
+ * 's' is NULL, disables STP.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. */
+int
+ofproto_set_stp(struct ofproto *ofproto,
+ const struct ofproto_stp_settings *s)
+{
+ return (ofproto->ofproto_class->set_stp
+ ? ofproto->ofproto_class->set_stp(ofproto, s)
+ : EOPNOTSUPP);
+}
+
+/* Retrieves STP status of 'ofproto' and stores it in 's'. If the
+ * 'enabled' member of 's' is false, then the other members are not
+ * meaningful.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. */
+int
+ofproto_get_stp_status(struct ofproto *ofproto,
+ struct ofproto_stp_status *s)
+{
+ return (ofproto->ofproto_class->get_stp_status
+ ? ofproto->ofproto_class->get_stp_status(ofproto, s)
+ : EOPNOTSUPP);
+}
+
+/* Configures STP on 'ofp_port' of 'ofproto' using the settings defined
+ * in 's'. The caller is responsible for assigning STP port numbers
+ * (using the 'port_num' member in the range of 1 through 255, inclusive)
+ * and ensuring there are no duplicates. If the 's' is NULL, then STP
+ * is disabled on the port.
+ *
+ * Returns 0 if successful, otherwise a positive errno value.*/
+int
+ofproto_port_set_stp(struct ofproto *ofproto, uint16_t ofp_port,
+ const struct ofproto_port_stp_settings *s)
+{
+ struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+ if (!ofport) {
+ VLOG_WARN("%s: cannot configure STP on nonexistent port %"PRIu16,
+ ofproto->name, ofp_port);
+ return ENODEV;
+ }
+
+ return (ofproto->ofproto_class->set_stp_port
+ ? ofproto->ofproto_class->set_stp_port(ofport, s)
+ : EOPNOTSUPP);
+}
+
+/* Retrieves STP port status of 'ofp_port' on 'ofproto' and stores it in
+ * 's'. If the 'enabled' member in 's' is false, then the other members
+ * are not meaningful.
+ *
+ * Returns 0 if successful, otherwise a positive errno value.*/
+int
+ofproto_port_get_stp_status(struct ofproto *ofproto, uint16_t ofp_port,
+ struct ofproto_port_stp_status *s)
+{
+ struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+ if (!ofport) {
+ VLOG_WARN("%s: cannot get STP status on nonexistent port %"PRIu16,
+ ofproto->name, ofp_port);
+ return ENODEV;
+ }
+
+ return (ofproto->ofproto_class->get_stp_port_status
+ ? ofproto->ofproto_class->get_stp_port_status(ofport, s)
+ : EOPNOTSUPP);
+}
+\f
/* Connectivity Fault Management configuration. */
/* Clears the CFM configuration from 'ofp_port' on 'ofproto'. */
/* Returns true if 'aux' is a registered bundle that is currently in use as the
* output for a mirror. */
bool
-ofproto_is_mirror_output_bundle(struct ofproto *ofproto, void *aux)
+ofproto_is_mirror_output_bundle(const struct ofproto *ofproto, void *aux)
{
return (ofproto->ofproto_class->is_mirror_output_bundle
? ofproto->ofproto_class->is_mirror_output_bundle(ofproto, aux)
}
}
-/* Updates 'port' within 'ofproto' with the new 'netdev' and 'opp'.
+/* Updates 'port' with new 'opp' description.
*
* Does not handle a name or port number change. The caller must implement
* such a change as a delete followed by an add. */
connmgr_send_port_status(port->ofproto->connmgr, &port->opp, OFPPR_MODIFY);
}
+/* Update OpenFlow 'state' in 'port' and notify controller. */
+void
+ofproto_port_set_state(struct ofport *port, ovs_be32 state)
+{
+ if (port->opp.state != state) {
+ port->opp.state = state;
+ connmgr_send_port_status(port->ofproto->connmgr, &port->opp,
+ OFPPR_MODIFY);
+ }
+}
+
void
ofproto_port_unregister(struct ofproto *ofproto, uint16_t ofp_port)
{
struct ofport *port = ofproto_get_port(ofproto, ofp_port);
if (port) {
+ if (port->ofproto->ofproto_class->set_stp_port) {
+ port->ofproto->ofproto_class->set_stp_port(port, NULL);
+ }
if (port->ofproto->ofproto_class->set_cfm) {
port->ofproto->ofproto_class->set_cfm(port, NULL);
}
assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
- flow_extract(packet, 0, in_port, &flow);
+ flow_extract(packet, 0, 0, in_port, &flow);
return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
}
osf->n_buffers = htonl(pktbuf_capacity());
osf->n_tables = ofproto->n_tables;
osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS |
- OFPC_PORT_STATS);
+ OFPC_PORT_STATS | OFPC_QUEUE_STATS);
if (arp_match_ip) {
osf->capabilities |= htonl(OFPC_ARP_MATCH_IP);
}
handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
- struct ofpbuf *buf;
struct ofp_switch_config *osc;
- uint16_t flags;
- bool drop_frags;
-
- /* Figure out flags. */
- drop_frags = ofproto->ofproto_class->get_drop_frags(ofproto);
- flags = drop_frags ? OFPC_FRAG_DROP : OFPC_FRAG_NORMAL;
+ struct ofpbuf *buf;
/* Send reply. */
osc = make_openflow_xid(sizeof *osc, OFPT_GET_CONFIG_REPLY, oh->xid, &buf);
- osc->flags = htons(flags);
+ osc->flags = htons(ofproto->frag_handling);
osc->miss_send_len = htons(ofconn_get_miss_send_len(ofconn));
ofconn_send_reply(ofconn, buf);
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
uint16_t flags = ntohs(osc->flags);
- if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
- && ofconn_get_role(ofconn) != NX_ROLE_SLAVE) {
- switch (flags & OFPC_FRAG_MASK) {
- case OFPC_FRAG_NORMAL:
- ofproto->ofproto_class->set_drop_frags(ofproto, false);
- break;
- case OFPC_FRAG_DROP:
- ofproto->ofproto_class->set_drop_frags(ofproto, true);
- break;
- default:
- VLOG_WARN_RL(&rl, "requested bad fragment mode (flags=%"PRIx16")",
- osc->flags);
- break;
+ if (ofconn_get_type(ofconn) != OFCONN_PRIMARY
+ || ofconn_get_role(ofconn) != NX_ROLE_SLAVE) {
+ enum ofp_config_flags cur = ofproto->frag_handling;
+ enum ofp_config_flags next = flags & OFPC_FRAG_MASK;
+
+ assert((cur & OFPC_FRAG_MASK) == cur);
+ if (cur != next) {
+ if (ofproto->ofproto_class->set_frag_handling(ofproto, next)) {
+ ofproto->frag_handling = next;
+ } else {
+ VLOG_WARN_RL(&rl, "%s: unsupported fragment handling mode %s",
+ ofproto->name,
+ ofputil_frag_handling_to_string(next));
+ }
}
}
/* Checks whether 'ofconn' is a slave controller. If so, returns an OpenFlow
* error message code (composed with ofp_mkerr()) for the caller to propagate
- * upward. Otherwise, returns 0.
- *
- * The log message mentions 'msg_type'. */
+ * upward. Otherwise, returns 0. */
static int
-reject_slave_controller(struct ofconn *ofconn, const char *msg_type)
+reject_slave_controller(const struct ofconn *ofconn)
{
if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
&& ofconn_get_role(ofconn) == NX_ROLE_SLAVE) {
- static struct vlog_rate_limit perm_rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&perm_rl, "rejecting %s message from slave controller",
- msg_type);
-
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
} else {
return 0;
struct ofpbuf request;
struct flow flow;
size_t n_ofp_actions;
+ uint16_t in_port;
int error;
COVERAGE_INC(ofproto_packet_out);
- error = reject_slave_controller(ofconn, "OFPT_PACKET_OUT");
+ error = reject_slave_controller(ofconn);
if (error) {
return error;
}
buffer = NULL;
}
+ /* Get in_port and partially validate it.
+ *
+ * We don't know what range of ports the ofproto actually implements, but
+ * we do know that only certain reserved ports (numbered OFPP_MAX and
+ * above) are valid. */
+ in_port = ntohs(opo->in_port);
+ if (in_port >= OFPP_MAX && in_port != OFPP_LOCAL && in_port != OFPP_NONE) {
+ return ofp_mkerr_nicira(OFPET_BAD_REQUEST, NXBRC_BAD_IN_PORT);
+ }
+
/* Send out packet. */
- flow_extract(&payload, 0, ntohs(opo->in_port), &flow);
+ flow_extract(&payload, 0, 0, in_port, &flow);
error = p->ofproto_class->packet_out(p, &payload, &flow,
ofp_actions, n_ofp_actions);
ofpbuf_delete(buffer);
struct ofport *port;
int error;
- error = reject_slave_controller(ofconn, "OFPT_PORT_MOD");
+ error = reject_slave_controller(ofconn);
if (error) {
return error;
}
*nsec = (msecs % 1000) * (1000 * 1000);
}
+/* Checks whether 'table_id' is 0xff or a valid table ID in 'ofproto'. Returns
+ * 0 if 'table_id' is OK, otherwise an OpenFlow error code. */
+static int
+check_table_id(const struct ofproto *ofproto, uint8_t table_id)
+{
+ return (table_id == 0xff || table_id < ofproto->n_tables
+ ? 0
+ : ofp_mkerr_nicira(OFPET_BAD_REQUEST, NXBRC_BAD_TABLE_ID));
+
+}
+
static struct classifier *
first_matching_table(struct ofproto *ofproto, uint8_t table_id)
{
} else if (table_id < ofproto->n_tables) {
return &ofproto->tables[table_id];
} else {
- /* It would probably be better to reply with an error but there doesn't
- * seem to be any appropriate value, so that might just be
- * confusing. */
- VLOG_WARN_RL(&rl, "controller asked for invalid table %"PRIu8,
- table_id);
return NULL;
}
}
* - If TABLE_ID is the number of a table in OFPROTO, then the loop iterates
* only once, for that table.
*
- * - Otherwise, TABLE_ID isn't valid for OFPROTO, so ofproto logs a warning
- * and does not enter the loop at all.
+ * - Otherwise, TABLE_ID isn't valid for OFPROTO, so the loop won't be
+ * entered at all. (Perhaps you should have validated TABLE_ID with
+ * check_table_id().)
*
* All parameters are evaluated multiple times.
*/
struct list *rules)
{
struct classifier *cls;
+ int error;
+
+ error = check_table_id(ofproto, table_id);
+ if (error) {
+ return error;
+ }
list_init(rules);
FOR_EACH_MATCHING_TABLE (cls, table_id, ofproto) {
struct list *rules)
{
struct classifier *cls;
+ int error;
+
+ error = check_table_id(ofproto, table_id);
+ if (error) {
+ return error;
+ }
list_init(rules);
FOR_EACH_MATCHING_TABLE (cls, table_id, ofproto) {
struct rule *rule;
int error;
- /* Check for overlap, if requested. */
- if (fm->flags & OFPFF_CHECK_OVERLAP) {
- struct classifier *cls;
-
- FOR_EACH_MATCHING_TABLE (cls, fm->table_id, ofproto) {
- if (classifier_rule_overlaps(cls, &fm->cr)) {
- return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
- }
- }
+ error = check_table_id(ofproto, fm->table_id);
+ if (error) {
+ return error;
}
/* Pick table. */
return ofp_mkerr_nicira(OFPET_FLOW_MOD_FAILED, NXFMFC_BAD_TABLE_ID);
}
+ /* Check for overlap, if requested. */
+ if (fm->flags & OFPFF_CHECK_OVERLAP
+ && classifier_rule_overlaps(table, &fm->cr)) {
+ return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP);
+ }
+
/* Serialize against pending deletion. */
if (is_flow_deletion_pending(ofproto, &fm->cr, table - ofproto->tables)) {
return OFPROTO_POSTPONE;
struct ofputil_flow_mod fm;
int error;
- error = reject_slave_controller(ofconn, "flow_mod");
+ error = reject_slave_controller(ofconn);
if (error) {
return error;
}
uint32_t role;
if (ofconn_get_type(ofconn) != OFCONN_PRIMARY) {
- VLOG_WARN_RL(&rl, "ignoring role request on service connection");
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_EPERM);
}
role = ntohl(nrr->role);
if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
&& role != NX_ROLE_SLAVE) {
- VLOG_WARN_RL(&rl, "received request for unknown role %"PRIu32, role);
-
- /* There's no good error code for this. */
- return ofp_mkerr(OFPET_BAD_REQUEST, -1);
+ return ofp_mkerr_nicira(OFPET_BAD_REQUEST, NXBRC_BAD_ROLE);
}
if (ofconn_get_role(ofconn) != role
case OFPUTIL_NXST_FLOW_REPLY:
case OFPUTIL_NXST_AGGREGATE_REPLY:
default:
- if (VLOG_IS_WARN_ENABLED()) {
- char *s = ofp_to_string(oh, ntohs(oh->length), 2);
- VLOG_DBG_RL(&rl, "OpenFlow message ignored: %s", s);
- free(s);
- }
if (oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY) {
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT);
} else {
}
registered = true;
- unixctl_command_register("ofproto/list", ofproto_unixctl_list, NULL);
+ unixctl_command_register("ofproto/list", "", ofproto_unixctl_list, NULL);
}