const struct ofproto_class *class;
struct ofproto *ofproto;
int error;
+ int i;
*ofprotop = NULL;
ofproto->ofp_port_ids = bitmap_allocate(ofproto->max_ports);
bitmap_set1(ofproto->ofp_port_ids, 0);
+ /* Check that hidden tables, if any, are at the end. */
assert(ofproto->n_tables);
+ for (i = 0; i + 1 < ofproto->n_tables; i++) {
+ enum oftable_flags flags = ofproto->tables[i].flags;
+ enum oftable_flags next_flags = ofproto->tables[i + 1].flags;
+
+ assert(!(flags & OFTABLE_HIDDEN) || next_flags & OFTABLE_HIDDEN);
+ }
ofproto->datapath_id = pick_datapath_id(ofproto);
init_ports(ofproto);
void
ofproto_set_controllers(struct ofproto *p,
const struct ofproto_controller *controllers,
- size_t n_controllers)
+ size_t n_controllers, uint32_t allowed_versions)
{
- connmgr_set_controllers(p->connmgr, controllers, n_controllers);
+ connmgr_set_controllers(p->connmgr, controllers, n_controllers,
+ allowed_versions);
}
void
}
}
+int
+ofproto_type_run(const char *datapath_type)
+{
+ const struct ofproto_class *class;
+ int error;
+
+ datapath_type = ofproto_normalize_type(datapath_type);
+ class = ofproto_class_find__(datapath_type);
+
+ error = class->type_run ? class->type_run(datapath_type) : 0;
+ if (error && error != EAGAIN) {
+ VLOG_ERR_RL(&rl, "%s: type_run failed (%s)",
+ datapath_type, strerror(error));
+ }
+ return error;
+}
+
+int
+ofproto_type_run_fast(const char *datapath_type)
+{
+ const struct ofproto_class *class;
+ int error;
+
+ datapath_type = ofproto_normalize_type(datapath_type);
+ class = ofproto_class_find__(datapath_type);
+
+ error = class->type_run_fast ? class->type_run_fast(datapath_type) : 0;
+ if (error && error != EAGAIN) {
+ VLOG_ERR_RL(&rl, "%s: type_run_fast failed (%s)",
+ datapath_type, strerror(error));
+ }
+ return error;
+}
+
+void
+ofproto_type_wait(const char *datapath_type)
+{
+ const struct ofproto_class *class;
+
+ datapath_type = ofproto_normalize_type(datapath_type);
+ class = ofproto_class_find__(datapath_type);
+
+ if (class->type_wait) {
+ class->type_wait(datapath_type);
+ }
+}
+
int
ofproto_run(struct ofproto *p)
{
return dump->error == EOF ? 0 : dump->error;
}
+/* Returns the type to pass to netdev_open() when a datapath of type
+ * 'datapath_type' has a port of type 'port_type', for a few special
+ * cases when a netdev type differs from a port type. For example, when
+ * using the userspace datapath, a port of type "internal" needs to be
+ * opened as "tap".
+ *
+ * Returns either 'type' itself or a string literal, which must not be
+ * freed. */
+const char *
+ofproto_port_open_type(const char *datapath_type, const char *port_type)
+{
+ const struct ofproto_class *class;
+
+ datapath_type = ofproto_normalize_type(datapath_type);
+ class = ofproto_class_find__(datapath_type);
+ if (!class) {
+ return port_type;
+ }
+
+ return (class->port_open_type
+ ? class->port_open_type(datapath_type, port_type)
+ : port_type);
+}
+
/* Attempts to add 'netdev' as a port on 'ofproto'. If 'ofp_portp' is
* non-null and '*ofp_portp' is not OFPP_NONE, attempts to use that as
* the port's OpenFlow port number.
* flows. */
while (ofp_port >= ofproto->max_ports) {
for (ofproto->alloc_port_no++;
- ofproto->alloc_port_no < ofproto->max_ports; ) {
+ ofproto->alloc_port_no < ofproto->max_ports;
+ ofproto->alloc_port_no++) {
if (!bitmap_is_set(ofproto->ofp_port_ids,
ofproto->alloc_port_no)) {
ofp_port = ofproto->alloc_port_no;
pp->state = netdev_get_carrier(netdev) ? 0 : OFPUTIL_PS_LINK_DOWN;
netdev_get_features(netdev, &pp->curr, &pp->advertised,
&pp->supported, &pp->peer);
- pp->curr_speed = netdev_features_to_bps(pp->curr);
- pp->max_speed = netdev_features_to_bps(pp->supported);
+ pp->curr_speed = netdev_features_to_bps(pp->curr, 0);
+ pp->max_speed = netdev_features_to_bps(pp->supported, 0);
return netdev;
}
bool
ofproto_rule_has_out_port(const struct rule *rule, uint16_t port)
{
- return (port == OFPP_NONE
+ return (port == OFPP_ANY
|| ofpacts_output_to_port(rule->ofpacts, rule->ofpacts_len, port));
}
/* Executes the actions indicated by 'rule' on 'packet' and credits 'rule''s
* statistics appropriately. 'packet' must have at least sizeof(struct
- * ofp_packet_in) bytes of headroom.
+ * ofp10_packet_in) bytes of headroom.
*
* 'packet' doesn't necessarily have to match 'rule'. 'rule' will be credited
* with statistics for 'packet' either way.
{
struct flow flow;
- assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
+ assert(ofpbuf_headroom(packet) >= sizeof(struct ofp10_packet_in));
- flow_extract(packet, 0, NULL, in_port, &flow);
+ flow_extract(packet, 0, 0, NULL, in_port, &flow);
return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
}
struct ofport *port;
bool arp_match_ip;
struct ofpbuf *b;
+ int n_tables;
+ int i;
ofproto->ofproto_class->get_features(ofproto, &arp_match_ip,
&features.actions);
assert(features.actions & OFPUTIL_A_OUTPUT); /* sanity check */
+ /* Count only non-hidden tables in the number of tables. (Hidden tables,
+ * if present, are always at the end.) */
+ n_tables = ofproto->n_tables;
+ for (i = 0; i < ofproto->n_tables; i++) {
+ if (ofproto->tables[i].flags & OFTABLE_HIDDEN) {
+ n_tables = i;
+ break;
+ }
+ }
+
features.datapath_id = ofproto->datapath_id;
features.n_buffers = pktbuf_capacity();
- features.n_tables = ofproto->n_tables;
+ features.n_tables = n_tables;
features.capabilities = (OFPUTIL_C_FLOW_STATS | OFPUTIL_C_TABLE_STATS |
OFPUTIL_C_PORT_STATS | OFPUTIL_C_QUEUE_STATS);
if (arp_match_ip) {
features.capabilities |= OFPUTIL_C_ARP_MATCH_IP;
}
-
+ /* FIXME: Fill in proper features.auxiliary_id for auxiliary connections */
+ features.auxiliary_id = 0;
b = ofputil_encode_switch_features(&features, ofconn_get_protocol(ofconn),
oh->xid);
HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
buf = ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY, oh, 0);
osc = ofpbuf_put_uninit(buf, sizeof *osc);
flags = ofproto->frag_handling;
- if (ofconn_get_invalid_ttl_to_controller(ofconn)) {
+ /* OFPC_INVALID_TTL_TO_CONTROLLER is deprecated in OF 1.3 */
+ if (oh->version < OFP13_VERSION
+ && ofconn_get_invalid_ttl_to_controller(ofconn)) {
flags |= OFPC_INVALID_TTL_TO_CONTROLLER;
}
osc->flags = htons(flags);
}
}
}
+ /* OFPC_INVALID_TTL_TO_CONTROLLER is deprecated in OF 1.3 */
ofconn_set_invalid_ttl_to_controller(ofconn,
- (flags & OFPC_INVALID_TTL_TO_CONTROLLER));
+ (oh->version < OFP13_VERSION
+ && flags & OFPC_INVALID_TTL_TO_CONTROLLER));
ofconn_set_miss_send_len(ofconn, ntohs(osc->miss_send_len));
}
/* Verify actions against packet, then send packet if successful. */
- flow_extract(payload, 0, NULL, po.in_port, &flow);
+ flow_extract(payload, 0, 0, NULL, po.in_port, &flow);
error = ofpacts_check(po.ofpacts, po.ofpacts_len, &flow, p->max_ports);
if (!error) {
error = p->ofproto_class->packet_out(p, payload, &flow,
struct ofproto *p = ofconn_get_ofproto(ofconn);
struct ofp12_table_stats *ots;
struct ofpbuf *msg;
+ int n_tables;
size_t i;
/* Set up default values.
p->ofproto_class->get_tables(p, ots);
+ /* Post-process the tables, dropping hidden tables. */
+ n_tables = p->n_tables;
for (i = 0; i < p->n_tables; i++) {
const struct oftable *table = &p->tables[i];
+ if (table->flags & OFTABLE_HIDDEN) {
+ n_tables = i;
+ break;
+ }
+
if (table->name) {
ovs_strzcpy(ots[i].name, table->name, sizeof ots[i].name);
}
}
}
- msg = ofputil_encode_table_stats_reply(ots, p->n_tables, request);
+ msg = ofputil_encode_table_stats_reply(ots, n_tables, request);
ofconn_send_reply(ofconn, msg);
free(ots);
}
ofpmp_init(&replies, request);
- if (port_no != OFPP_NONE) {
+ if (port_no != OFPP_ANY) {
port = ofproto_get_port(p, port_no);
if (port) {
append_port_stat(port, &replies);
* OpenFlow OFPFC_MODIFY and OFPFC_DELETE requests and puts them on list
* 'rules'.
*
- * If 'out_port' is anything other than OFPP_NONE, then only rules that output
+ * If 'out_port' is anything other than OFPP_ANY, then only rules that output
* to 'out_port' are included.
*
* Hidden rules are always omitted.
* OpenFlow OFPFC_MODIFY_STRICT and OFPFC_DELETE_STRICT requests and puts them
* on list 'rules'.
*
- * If 'out_port' is anything other than OFPP_NONE, then only rules that output
+ * If 'out_port' is anything other than OFPP_ANY, then only rules that output
* to 'out_port' are included.
*
* Hidden rules are always omitted.
&fs.byte_count);
fs.ofpacts = rule->ofpacts;
fs.ofpacts_len = rule->ofpacts_len;
+ fs.flags = 0;
+ if (rule->send_flow_removed) {
+ fs.flags |= OFPFF_SEND_FLOW_REM;
+ /* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
+ and OFPFF13_NO_BYT_COUNTS */
+ }
ofputil_append_flow_stats_reply(&fs, &replies);
}
ofconn_send_replies(ofconn, &replies);
return error;
}
- if (oqsr.port_no == OFPP_ALL) {
+ if (oqsr.port_no == OFPP_ANY) {
error = OFPERR_OFPQOFC_BAD_QUEUE;
HMAP_FOR_EACH (port, hmap_node, &ofproto->ports) {
if (!handle_queue_stats_for_port(port, oqsr.queue_id, &cbdata)) {
return OFPERR_OFPFMFC_OVERLAP;
}
+ /* FIXME: Implement OFPFF12_RESET_COUNTS */
+
rule->ofproto = ofproto;
rule->pending = NULL;
rule->flow_cookie = fm->new_cookie;
rule->hard_timeout = fm->hard_timeout;
rule->table_id = table - ofproto->tables;
rule->send_flow_removed = (fm->flags & OFPFF_SEND_FLOW_REM) != 0;
+ /* FIXME: Implement OF 1.3 flags OFPFF13_NO_PKT_COUNTS
+ and OFPFF13_NO_BYT_COUNTS */
rule->ofpacts = xmemdup(fm->ofpacts, fm->ofpacts_len);
rule->ofpacts_len = fm->ofpacts_len;
rule->evictable = true;
bool actions_changed;
ovs_be64 new_cookie;
+ /* FIXME: Implement OFPFF12_RESET_COUNTS */
+
if (rule_is_modifiable(rule)) {
/* At least one rule is modifiable, don't report EPERM error. */
error = 0;
error = collect_rules_loose(ofproto, fm->table_id, &fm->match,
fm->cookie, fm->cookie_mask,
- OFPP_NONE, &rules);
+ OFPP_ANY, &rules);
if (error) {
return error;
} else if (list_is_empty(&rules)) {
error = collect_rules_strict(ofproto, fm->table_id, &fm->match,
fm->priority, fm->cookie, fm->cookie_mask,
- OFPP_NONE, &rules);
+ OFPP_ANY, &rules);
if (error) {
return error;
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn),
&ofpacts);
- if (error) {
- goto exit_free_ofpacts;
- }
-
- if (fm.flags & OFPFF10_EMERG) {
- /* We do not support the OpenFlow 1.0 emergency flow cache, which
- * is not required in OpenFlow 1.0.1 and removed from OpenFlow 1.1.
- * There is no good error code, so just state that the flow table
- * is full. */
- error = OFPERR_OFPFMFC_TABLE_FULL;
- }
if (!error) {
error = ofpacts_check(fm.ofpacts, fm.ofpacts_len,
&fm.match.flow, ofproto->max_ports);
if (error) {
goto exit_free_ofpacts;
}
-
+
/* Record the operation for logging a summary report. */
switch (fm.command) {
case OFPFC_ADD:
case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
return handle_flow_monitor_request(ofconn, oh);
+ /* FIXME: Change the following once they are implemented: */
+ case OFPTYPE_GET_ASYNC_REQUEST:
+ case OFPTYPE_METER_MOD:
+ case OFPTYPE_GROUP_REQUEST:
+ case OFPTYPE_GROUP_DESC_REQUEST:
+ case OFPTYPE_GROUP_FEATURES_REQUEST:
+ case OFPTYPE_METER_REQUEST:
+ case OFPTYPE_METER_CONFIG_REQUEST:
+ case OFPTYPE_METER_FEATURES_REQUEST:
+ case OFPTYPE_TABLE_FEATURES_REQUEST:
+ return OFPERR_OFPBRC_BAD_TYPE;
+
case OFPTYPE_HELLO:
case OFPTYPE_ERROR:
case OFPTYPE_FEATURES_REPLY:
case OFPTYPE_FLOW_MONITOR_PAUSED:
case OFPTYPE_FLOW_MONITOR_RESUMED:
case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
+ case OFPTYPE_GET_ASYNC_REPLY:
+ case OFPTYPE_GROUP_REPLY:
+ case OFPTYPE_GROUP_DESC_REPLY:
+ case OFPTYPE_GROUP_FEATURES_REPLY:
+ case OFPTYPE_METER_REPLY:
+ case OFPTYPE_METER_CONFIG_REPLY:
+ case OFPTYPE_METER_FEATURES_REPLY:
+ case OFPTYPE_TABLE_FEATURES_REPLY:
default:
return OFPERR_OFPBRC_BAD_TYPE;
}