/* Fields in a rule. */
#define CLS_FIELDS \
- /* struct flow all-caps */ \
- /* member name name */ \
- /* ----------- -------- */ \
- CLS_FIELD(tun_id, TUN_ID) \
- CLS_FIELD(metadata, METADATA) \
- CLS_FIELD(nw_src, NW_SRC) \
- CLS_FIELD(nw_dst, NW_DST) \
- CLS_FIELD(in_port, IN_PORT) \
- CLS_FIELD(vlan_tci, VLAN_TCI) \
- CLS_FIELD(dl_type, DL_TYPE) \
- CLS_FIELD(tp_src, TP_SRC) \
- CLS_FIELD(tp_dst, TP_DST) \
- CLS_FIELD(dl_src, DL_SRC) \
- CLS_FIELD(dl_dst, DL_DST) \
- CLS_FIELD(nw_proto, NW_PROTO) \
- CLS_FIELD(nw_tos, NW_DSCP)
+ /* struct flow all-caps */ \
+ /* member name name */ \
+ /* ----------- -------- */ \
+ CLS_FIELD(tunnel.tun_id, TUN_ID) \
+ CLS_FIELD(metadata, METADATA) \
+ CLS_FIELD(nw_src, NW_SRC) \
+ CLS_FIELD(nw_dst, NW_DST) \
+ CLS_FIELD(in_port, IN_PORT) \
+ CLS_FIELD(vlan_tci, VLAN_TCI) \
+ CLS_FIELD(dl_type, DL_TYPE) \
+ CLS_FIELD(tp_src, TP_SRC) \
+ CLS_FIELD(tp_dst, TP_DST) \
+ CLS_FIELD(dl_src, DL_SRC) \
+ CLS_FIELD(dl_dst, DL_DST) \
+ CLS_FIELD(nw_proto, NW_PROTO) \
+ CLS_FIELD(nw_tos, NW_DSCP)
/* Field indexes.
*
return rule ? CONTAINER_OF(rule, struct test_rule, cls_rule) : NULL;
}
+static void
+test_rule_destroy(struct test_rule *rule)
+{
+ if (rule) {
+ cls_rule_destroy(&rule->cls_rule);
+ free(rule);
+ }
+}
+
static struct test_rule *make_rule(int wc_fields, unsigned int priority,
int value_pat);
static void free_rule(struct test_rule *);
size_t i;
for (i = 0; i < tcls->n_rules; i++) {
- free(tcls->rules[i]);
+ test_rule_destroy(tcls->rules[i]);
}
free(tcls->rules);
}
for (i = 0; i < cls->n_rules; i++) {
struct test_rule *pos = cls->rules[i];
if (pos == rule) {
- free(pos);
+ test_rule_destroy(pos);
+
memmove(&cls->rules[i], &cls->rules[i + 1],
sizeof *cls->rules * (cls->n_rules - i - 1));
+
cls->n_rules--;
return;
}
eq = !((fixed->vlan_tci ^ wild.flow.vlan_tci)
& wild.wc.masks.vlan_tci);
} else if (f_idx == CLS_F_IDX_TUN_ID) {
- eq = !((fixed->tun_id ^ wild.flow.tun_id)
- & wild.wc.masks.tun_id);
+ eq = !((fixed->tunnel.tun_id ^ wild.flow.tunnel.tun_id)
+ & wild.wc.masks.tunnel.tun_id);
} else if (f_idx == CLS_F_IDX_METADATA) {
eq = !((fixed->metadata ^ wild.flow.metadata)
& wild.wc.masks.metadata);
memset(&flow, 0, sizeof flow);
flow.nw_src = nw_src_values[get_value(&x, N_NW_SRC_VALUES)];
flow.nw_dst = nw_dst_values[get_value(&x, N_NW_DST_VALUES)];
- flow.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)];
+ flow.tunnel.tun_id = tun_id_values[get_value(&x, N_TUN_ID_VALUES)];
flow.metadata = metadata_values[get_value(&x, N_METADATA_VALUES)];
flow.in_port = in_port_values[get_value(&x, N_IN_PORT_VALUES)];
flow.vlan_tci = vlan_tci_values[get_value(&x, N_VLAN_TCI_VALUES)];
HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
const struct cls_rule *head;
+ unsigned int max_priority = 0;
+ unsigned int max_count = 0;
assert(!hmap_is_empty(&table->rules));
unsigned int prev_priority = UINT_MAX;
const struct cls_rule *rule;
+ if (head->priority > max_priority) {
+ max_priority = head->priority;
+ max_count = 1;
+ } else if (head->priority == max_priority) {
+ ++max_count;
+ }
+
found_rules++;
LIST_FOR_EACH (rule, list, &head->list) {
assert(rule->priority < prev_priority);
+ assert(rule->priority <= table->max_priority);
+
prev_priority = rule->priority;
found_rules++;
found_dups++;
assert(classifier_find_rule_exactly(cls, rule) == rule);
}
}
+ assert(table->max_priority == max_priority);
+ assert(table->max_count == max_count);
}
assert(found_tables == hmap_count(&cls->tables));
} else if (f_idx == CLS_F_IDX_VLAN_TCI) {
match.wc.masks.vlan_tci = htons(UINT16_MAX);
} else if (f_idx == CLS_F_IDX_TUN_ID) {
- match.wc.masks.tun_id = htonll(UINT64_MAX);
+ match.wc.masks.tunnel.tun_id = htonll(UINT64_MAX);
} else if (f_idx == CLS_F_IDX_METADATA) {
match.wc.masks.metadata = htonll(UINT64_MAX);
} else if (f_idx == CLS_F_IDX_NW_DSCP) {
minimask_destroy(&minimask);
}
+
+ minimask_destroy(&minicatchall);
}
static void
minimask_destroy(&minimask);
minimask_destroy(&minimask2);
}
+
+ minimask_destroy(&minicatchall);
}
\f
static const struct command commands[] = {