Initial OpenFlow 1.3 support
[openvswitch] / ofproto / ofproto.c
index cd09bbd1146d70beec07d1ca055865c8d202dd63..bc3eb54123603f9878cfdd7696fc424f7112ed46 100644 (file)
@@ -374,6 +374,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     const struct ofproto_class *class;
     struct ofproto *ofproto;
     int error;
+    int i;
 
     *ofprotop = NULL;
 
@@ -444,7 +445,14 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     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);
@@ -510,9 +518,10 @@ ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
 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
@@ -1097,6 +1106,53 @@ process_port_change(struct ofproto *ofproto, int error, char *devname)
     }
 }
 
+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)
 {
@@ -1377,6 +1433,30 @@ ofproto_port_dump_done(struct ofproto_port_dump *dump)
     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.
@@ -1586,7 +1666,8 @@ alloc_ofp_port(struct ofproto *ofproto, const char *netdev_name)
          * 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;
@@ -1652,8 +1733,8 @@ ofport_open(struct ofproto *ofproto,
     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;
 }
@@ -2048,7 +2129,7 @@ ofproto_rule_destroy(struct rule *rule)
 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));
 }
 
@@ -2090,7 +2171,7 @@ rule_execute(struct rule *rule, uint16_t in_port, struct ofpbuf *packet)
 
     assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_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);
 }
 
@@ -2132,20 +2213,33 @@ handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
     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) {
@@ -2168,7 +2262,9 @@ handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
     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);
@@ -2201,8 +2297,10 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
             }
         }
     }
+    /* 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));
 
@@ -2267,7 +2365,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
     }
 
     /* 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,
@@ -2364,6 +2462,7 @@ handle_table_stats_request(struct ofconn *ofconn,
     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.
@@ -2392,9 +2491,16 @@ handle_table_stats_request(struct ofconn *ofconn,
 
     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);
         }
@@ -2404,7 +2510,7 @@ handle_table_stats_request(struct ofconn *ofconn,
         }
     }
 
-    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);
@@ -2441,7 +2547,7 @@ handle_port_stats_request(struct ofconn *ofconn,
     }
 
     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);
@@ -2558,7 +2664,7 @@ next_matching_table(const struct ofproto *ofproto,
  * 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.
@@ -2609,7 +2715,7 @@ exit:
  * 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.
@@ -2707,6 +2813,12 @@ handle_flow_stats_request(struct ofconn *ofconn,
                                                &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);
@@ -2953,7 +3065,7 @@ handle_queue_stats_request(struct ofconn *ofconn,
         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)) {
@@ -3073,6 +3185,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
         return OFPERR_OFPFMFC_OVERLAP;
     }
 
+    /* FIXME: Implement OFPFF12_RESET_COUNTS */
+
     rule->ofproto = ofproto;
     rule->pending = NULL;
     rule->flow_cookie = fm->new_cookie;
@@ -3081,6 +3195,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     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;
@@ -3166,6 +3282,8 @@ modify_flows__(struct ofproto *ofproto, struct ofconn *ofconn,
         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;
@@ -3226,7 +3344,7 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
 
     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)) {
@@ -3251,7 +3369,7 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
 
     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;
@@ -3415,17 +3533,6 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     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);
@@ -3436,7 +3543,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     if (error) {
         goto exit_free_ofpacts;
     }
-
+    
     /* Record the operation for logging a summary report. */
     switch (fm.command) {
     case OFPFC_ADD:
@@ -3994,6 +4101,18 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     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:
@@ -4013,6 +4132,14 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     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;
     }