ofproto: Fix uninitialized field in ofputil_flow_update.
[sliver-openvswitch.git] / ofproto / ofproto.c
index 8384308..e3b24c1 100644 (file)
@@ -1419,19 +1419,21 @@ ofproto_port_del(struct ofproto *ofproto, uint16_t ofp_port)
  *
  * This is a helper function for in-band control and fail-open. */
 void
-ofproto_add_flow(struct ofproto *ofproto, const struct cls_rule *cls_rule,
+ofproto_add_flow(struct ofproto *ofproto, const struct match *match,
+                 unsigned int priority,
                  const struct ofpact *ofpacts, size_t ofpacts_len)
 {
     const struct rule *rule;
 
-    rule = rule_from_cls_rule(classifier_find_rule_exactly(
-                                    &ofproto->tables[0].cls, cls_rule));
+    rule = rule_from_cls_rule(classifier_find_match_exactly(
+                                  &ofproto->tables[0].cls, match, priority));
     if (!rule || !ofpacts_equal(rule->ofpacts, rule->ofpacts_len,
                                 ofpacts, ofpacts_len)) {
         struct ofputil_flow_mod fm;
 
         memset(&fm, 0, sizeof fm);
-        fm.cr = *cls_rule;
+        fm.match = *match;
+        fm.priority = priority;
         fm.buffer_id = UINT32_MAX;
         fm.ofpacts = xmemdup(ofpacts, ofpacts_len);
         fm.ofpacts_len = ofpacts_len;
@@ -1456,12 +1458,13 @@ ofproto_flow_mod(struct ofproto *ofproto, const struct ofputil_flow_mod *fm)
  *
  * This is a helper function for in-band control and fail-open. */
 bool
-ofproto_delete_flow(struct ofproto *ofproto, const struct cls_rule *target)
+ofproto_delete_flow(struct ofproto *ofproto,
+                    const struct match *target, unsigned int priority)
 {
     struct rule *rule;
 
-    rule = rule_from_cls_rule(classifier_find_rule_exactly(
-                                  &ofproto->tables[0].cls, target));
+    rule = rule_from_cls_rule(classifier_find_match_exactly(
+                                  &ofproto->tables[0].cls, target, priority));
     if (!rule) {
         /* No such rule -> success. */
         return true;
@@ -1898,6 +1901,7 @@ static void
 ofproto_rule_destroy__(struct rule *rule)
 {
     if (rule) {
+        cls_rule_destroy(&rule->cr);
         free(rule->ofpacts);
         rule->ofproto->ofproto_class->rule_dealloc(rule);
     }
@@ -2126,10 +2130,11 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
         goto exit_free_ofpacts;
     }
     if (po.in_port >= p->max_ports && po.in_port < OFPP_MAX) {
-        error = OFPERR_NXBRC_BAD_IN_PORT;
+        error = OFPERR_OFPBRC_BAD_PORT;
         goto exit_free_ofpacts;
     }
 
+
     /* Get payload. */
     if (po.buffer_id != UINT32_MAX) {
         error = ofconn_pktbuf_retrieve(ofconn, po.buffer_id, &payload, NULL);
@@ -2237,16 +2242,30 @@ handle_table_stats_request(struct ofconn *ofconn,
                            const struct ofp_header *request)
 {
     struct ofproto *p = ofconn_get_ofproto(ofconn);
-    struct ofp10_table_stats *ots;
+    struct ofp12_table_stats *ots;
     struct ofpbuf *msg;
     size_t i;
 
-    msg = ofpraw_alloc_stats_reply(request, sizeof *ots * p->n_tables);
-    ots = ofpbuf_put_zeros(msg, sizeof *ots * p->n_tables);
+    /* Set up default values.
+     *
+     * ofp12_table_stats is used as a generic structure as
+     * it is able to hold all the fields for ofp10_table_stats
+     * and ofp11_table_stats (and of course itself).
+     */
+    ots = xcalloc(p->n_tables, sizeof *ots);
     for (i = 0; i < p->n_tables; i++) {
         ots[i].table_id = i;
         sprintf(ots[i].name, "table%zu", i);
-        ots[i].wildcards = htonl(OFPFW10_ALL);
+        ots[i].match = htonll(OFPXMT12_MASK);
+        ots[i].wildcards = htonll(OFPXMT12_MASK);
+        ots[i].write_actions = htonl(OFPAT12_OUTPUT);
+        ots[i].apply_actions = htonl(OFPAT12_OUTPUT);
+        ots[i].write_setfields = htonll(OFPXMT12_MASK);
+        ots[i].apply_setfields = htonll(OFPXMT12_MASK);
+        ots[i].metadata_match = htonll(UINT64_MAX);
+        ots[i].metadata_write = htonll(UINT64_MAX);
+        ots[i].instructions = htonl(OFPIT11_ALL);
+        ots[i].config = htonl(OFPTC11_TABLE_MISS_MASK);
         ots[i].max_entries = htonl(1000000); /* An arbitrary big number. */
         ots[i].active_count = htonl(classifier_count(&p->tables[i].cls));
     }
@@ -2265,7 +2284,11 @@ handle_table_stats_request(struct ofconn *ofconn,
         }
     }
 
+    msg = ofputil_encode_table_stats_reply(ots, p->n_tables, request);
     ofconn_send_reply(ofconn, msg);
+
+    free(ots);
+
     return 0;
 }
 
@@ -2358,7 +2381,7 @@ check_table_id(const struct ofproto *ofproto, uint8_t table_id)
 {
     return (table_id == 0xff || table_id < ofproto->n_tables
             ? 0
-            : OFPERR_NXBRC_BAD_TABLE_ID);
+            : OFPERR_OFPBRC_BAD_TABLE_ID);
 
 }
 
@@ -2432,11 +2455,12 @@ next_matching_table(const struct ofproto *ofproto,
  * Returns 0 on success, otherwise an OpenFlow error code. */
 static enum ofperr
 collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
-                    const struct cls_rule *match,
+                    const struct match *match,
                     ovs_be64 cookie, ovs_be64 cookie_mask,
                     uint16_t out_port, struct list *rules)
 {
     struct oftable *table;
+    struct cls_rule cr;
     enum ofperr error;
 
     error = check_table_id(ofproto, table_id);
@@ -2445,14 +2469,16 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
     }
 
     list_init(rules);
+    cls_rule_init(&cr, match, 0);
     FOR_EACH_MATCHING_TABLE (table, table_id, ofproto) {
         struct cls_cursor cursor;
         struct rule *rule;
 
-        cls_cursor_init(&cursor, &table->cls, match);
+        cls_cursor_init(&cursor, &table->cls, &cr);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
             if (rule->pending) {
-                return OFPROTO_POSTPONE;
+                error = OFPROTO_POSTPONE;
+                goto exit;
             }
             if (!ofproto_rule_is_hidden(rule)
                 && ofproto_rule_has_out_port(rule, out_port)
@@ -2461,7 +2487,10 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
             }
         }
     }
-    return 0;
+
+exit:
+    cls_rule_destroy(&cr);
+    return error;
 }
 
 /* Searches 'ofproto' for rules in table 'table_id' (or in all tables, if
@@ -2477,11 +2506,12 @@ collect_rules_loose(struct ofproto *ofproto, uint8_t table_id,
  * Returns 0 on success, otherwise an OpenFlow error code. */
 static enum ofperr
 collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
-                     const struct cls_rule *match,
+                     const struct match *match, unsigned int priority,
                      ovs_be64 cookie, ovs_be64 cookie_mask,
                      uint16_t out_port, struct list *rules)
 {
     struct oftable *table;
+    struct cls_rule cr;
     int error;
 
     error = check_table_id(ofproto, table_id);
@@ -2490,14 +2520,16 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
     }
 
     list_init(rules);
+    cls_rule_init(&cr, match, priority);
     FOR_EACH_MATCHING_TABLE (table, table_id, ofproto) {
         struct rule *rule;
 
         rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls,
-                                                               match));
+                                                               &cr));
         if (rule) {
             if (rule->pending) {
-                return OFPROTO_POSTPONE;
+                error = OFPROTO_POSTPONE;
+                goto exit;
             }
             if (!ofproto_rule_is_hidden(rule)
                 && ofproto_rule_has_out_port(rule, out_port)
@@ -2506,6 +2538,9 @@ collect_rules_strict(struct ofproto *ofproto, uint8_t table_id,
             }
         }
     }
+
+exit:
+    cls_rule_destroy(&cr);
     return 0;
 }
 
@@ -2547,7 +2582,8 @@ handle_flow_stats_request(struct ofconn *ofconn,
         long long int now = time_msec();
         struct ofputil_flow_stats fs;
 
-        fs.rule = rule->cr;
+        minimatch_expand(&rule->cr.match, &fs.match);
+        fs.priority = rule->cr.priority;
         fs.cookie = rule->flow_cookie;
         fs.table_id = rule->table_id;
         calc_flow_duration__(rule->created, now, &fs.duration_sec,
@@ -2869,6 +2905,7 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     struct oftable *table;
     struct ofopgroup *group;
     struct rule *victim;
+    struct cls_rule cr;
     struct rule *rule;
     int error;
 
@@ -2881,7 +2918,8 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     if (fm->table_id == 0xff) {
         uint8_t table_id;
         if (ofproto->ofproto_class->rule_choose_table) {
-            error = ofproto->ofproto_class->rule_choose_table(ofproto, &fm->cr,
+            error = ofproto->ofproto_class->rule_choose_table(ofproto,
+                                                              &fm->match,
                                                               &table_id);
             if (error) {
                 return error;
@@ -2894,33 +2932,38 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     } else if (fm->table_id < ofproto->n_tables) {
         table = &ofproto->tables[fm->table_id];
     } else {
-        return OFPERR_NXFMFC_BAD_TABLE_ID;
+        return OFPERR_OFPBRC_BAD_TABLE_ID;
     }
 
     if (table->flags & OFTABLE_READONLY) {
         return OFPERR_OFPBRC_EPERM;
     }
 
-    /* Check for overlap, if requested. */
-    if (fm->flags & OFPFF_CHECK_OVERLAP
-        && classifier_rule_overlaps(&table->cls, &fm->cr)) {
-        return OFPERR_OFPFMFC_OVERLAP;
+    /* Allocate new rule and initialize classifier rule. */
+    rule = ofproto->ofproto_class->rule_alloc();
+    if (!rule) {
+        VLOG_WARN_RL(&rl, "%s: failed to create rule (%s)",
+                     ofproto->name, strerror(error));
+        return ENOMEM;
     }
+    cls_rule_init(&rule->cr, &fm->match, fm->priority);
 
     /* Serialize against pending deletion. */
-    if (is_flow_deletion_pending(ofproto, &fm->cr, table - ofproto->tables)) {
+    if (is_flow_deletion_pending(ofproto, &cr, table - ofproto->tables)) {
+        cls_rule_destroy(&rule->cr);
+        ofproto->ofproto_class->rule_dealloc(rule);
         return OFPROTO_POSTPONE;
     }
 
-    /* Allocate new rule. */
-    rule = ofproto->ofproto_class->rule_alloc();
-    if (!rule) {
-        VLOG_WARN_RL(&rl, "%s: failed to create rule (%s)",
-                     ofproto->name, strerror(error));
-        return ENOMEM;
+    /* Check for overlap, if requested. */
+    if (fm->flags & OFPFF_CHECK_OVERLAP
+        && classifier_rule_overlaps(&table->cls, &rule->cr)) {
+        cls_rule_destroy(&rule->cr);
+        ofproto->ofproto_class->rule_dealloc(rule);
+        return OFPERR_OFPFMFC_OVERLAP;
     }
+
     rule->ofproto = ofproto;
-    rule->cr = fm->cr;
     rule->pending = NULL;
     rule->flow_cookie = fm->new_cookie;
     rule->created = rule->modified = rule->used = time_msec();
@@ -3060,7 +3103,7 @@ modify_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+    error = collect_rules_loose(ofproto, fm->table_id, &fm->match,
                                 fm->cookie, fm->cookie_mask,
                                 OFPP_NONE, &rules);
     if (error) {
@@ -3085,8 +3128,8 @@ modify_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     int error;
 
-    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
-                                 fm->cookie, fm->cookie_mask,
+    error = collect_rules_strict(ofproto, fm->table_id, &fm->match,
+                                 fm->priority, fm->cookie, fm->cookie_mask,
                                  OFPP_NONE, &rules);
 
     if (error) {
@@ -3142,7 +3185,7 @@ delete_flows_loose(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     enum ofperr error;
 
-    error = collect_rules_loose(ofproto, fm->table_id, &fm->cr,
+    error = collect_rules_loose(ofproto, fm->table_id, &fm->match,
                                 fm->cookie, fm->cookie_mask,
                                 fm->out_port, &rules);
     return (error ? error
@@ -3160,8 +3203,8 @@ delete_flow_strict(struct ofproto *ofproto, struct ofconn *ofconn,
     struct list rules;
     enum ofperr error;
 
-    error = collect_rules_strict(ofproto, fm->table_id, &fm->cr,
-                                 fm->cookie, fm->cookie_mask,
+    error = collect_rules_strict(ofproto, fm->table_id, &fm->match,
+                                 fm->priority, fm->cookie, fm->cookie_mask,
                                  fm->out_port, &rules);
     return (error ? error
             : list_is_singleton(&rules) ? delete_flows__(ofproto, ofconn,
@@ -3178,7 +3221,8 @@ ofproto_rule_send_removed(struct rule *rule, uint8_t reason)
         return;
     }
 
-    fr.rule = rule->cr;
+    minimatch_expand(&rule->cr.match, &fr.match);
+    fr.priority = rule->cr.priority;
     fr.cookie = rule->flow_cookie;
     fr.reason = reason;
     calc_flow_duration__(rule->created, time_msec(),
@@ -3263,7 +3307,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
     }
     if (!error) {
         error = ofpacts_check(fm.ofpacts, fm.ofpacts_len,
-                              &fm.cr.flow, ofproto->max_ports);
+                              &fm.match.flow, ofproto->max_ports);
     }
     if (!error) {
         error = handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
@@ -3489,6 +3533,7 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
 {
     struct ofoperation *op = rule->pending;
     struct ofputil_flow_update fu;
+    struct match match;
 
     if (op && op->type == OFOPERATION_ADD && !op->victim) {
         /* We'll report the final flow when the operation completes.  Reporting
@@ -3503,7 +3548,9 @@ ofproto_compose_flow_refresh_update(const struct rule *rule,
     fu.hard_timeout = rule->hard_timeout;
     fu.table_id = rule->table_id;
     fu.cookie = rule->flow_cookie;
-    fu.match = CONST_CAST(struct cls_rule *, &rule->cr);
+    minimatch_expand(&rule->cr.match, &match);
+    fu.match = &match;
+    fu.priority = rule->cr.priority;
     if (!(flags & NXFMF_ACTIONS)) {
         fu.ofpacts = NULL;
         fu.ofpacts_len = 0;
@@ -3606,12 +3653,14 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m,
     const struct ofproto *ofproto = ofconn_get_ofproto(m->ofconn);
     const struct ofoperation *op;
     const struct oftable *table;
+    struct cls_rule target;
 
+    cls_rule_init_from_minimatch(&target, &m->match, 0);
     FOR_EACH_MATCHING_TABLE (table, m->table_id, ofproto) {
         struct cls_cursor cursor;
         struct rule *rule;
 
-        cls_cursor_init(&cursor, &table->cls, &m->match);
+        cls_cursor_init(&cursor, &table->cls, &target);
         CLS_CURSOR_FOR_EACH (rule, cr, &cursor) {
             assert(!rule->pending); /* XXX */
             ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
@@ -3624,10 +3673,11 @@ ofproto_collect_ofmonitor_refresh_rules(const struct ofmonitor *m,
         if (((m->table_id == 0xff
               ? !(ofproto->tables[rule->table_id].flags & OFTABLE_HIDDEN)
               : m->table_id == rule->table_id))
-            && cls_rule_is_loose_match(&rule->cr, &m->match)) {
+            && cls_rule_is_loose_match(&rule->cr, &target.match)) {
             ofproto_collect_ofmonitor_refresh_rule(m, rule, seqno, rules);
         }
     }
+    cls_rule_destroy(&target);
 }
 
 static void
@@ -3991,12 +4041,13 @@ ofopgroup_complete(struct ofopgroup *group)
         switch (op->type) {
         case OFOPERATION_ADD:
             if (!op->error) {
+                uint16_t vid_mask;
+
                 ofproto_rule_destroy__(op->victim);
-                if ((rule->cr.wc.masks.vlan_tci & htons(VLAN_VID_MASK))
-                    == htons(VLAN_VID_MASK)) {
+                vid_mask = minimask_get_vid_mask(&rule->cr.match.mask);
+                if (vid_mask == VLAN_VID_MASK) {
                     if (ofproto->vlan_bitmap) {
-                        uint16_t vid = vlan_tci_to_vid(rule->cr.flow.vlan_tci);
-
+                        uint16_t vid = miniflow_get_vid(&rule->cr.match.flow);
                         if (!bitmap_is_set(ofproto->vlan_bitmap, vid)) {
                             bitmap_set1(ofproto->vlan_bitmap, vid);
                             ofproto->vlans_changed = true;
@@ -4330,17 +4381,19 @@ eviction_group_hash_rule(struct rule *rule)
 {
     struct oftable *table = &rule->ofproto->tables[rule->table_id];
     const struct mf_subfield *sf;
+    struct flow flow;
     uint32_t hash;
 
     hash = table->eviction_group_id_basis;
+    miniflow_expand(&rule->cr.match.flow, &flow);
     for (sf = table->eviction_fields;
          sf < &table->eviction_fields[table->n_eviction_fields];
          sf++)
     {
-        if (mf_are_prereqs_ok(sf->field, &rule->cr.flow)) {
+        if (mf_are_prereqs_ok(sf->field, &flow)) {
             union mf_value value;
 
-            mf_get_value(sf->field, &rule->cr.flow, &value);
+            mf_get_value(sf->field, &flow, &value);
             if (sf->ofs) {
                 bitwise_zero(&value, sf->field->n_bytes, 0, sf->ofs);
             }
@@ -4646,12 +4699,11 @@ ofproto_get_vlan_usage(struct ofproto *ofproto, unsigned long int *vlan_bitmap)
         const struct cls_table *table;
 
         HMAP_FOR_EACH (table, hmap_node, &oftable->cls.tables) {
-            if ((table->wc.masks.vlan_tci & htons(VLAN_VID_MASK))
-                == htons(VLAN_VID_MASK)) {
+            if (minimask_get_vid_mask(&table->mask) == VLAN_VID_MASK) {
                 const struct cls_rule *rule;
 
                 HMAP_FOR_EACH (rule, hmap_node, &table->rules) {
-                    uint16_t vid = vlan_tci_to_vid(rule->flow.vlan_tci);
+                    uint16_t vid = miniflow_get_vid(&rule->match.flow);
                     bitmap_set1(vlan_bitmap, vid);
                     bitmap_set1(ofproto->vlan_bitmap, vid);
                 }