This patch is done to enable in tree building of the ovn-utils python
wrapper. This is similar to what was done in:
ee89ea7b477bb4fd05137de03b2e8443807ed9f4

Signed-off-by: Aaron Rosen <aaronoro...@gmail.com>
---
 include/automake.mk             |   1 +
 include/ovn/actions.h           | 141 ++++++++++++
 include/ovn/automake.mk         |   5 +
 include/ovn/expr.h              | 474 ++++++++++++++++++++++++++++++++++++++++
 include/ovn/lex.h               | 139 ++++++++++++
 ovn/controller/lflow.c          |   4 +-
 ovn/controller/ofctrl.c         |   2 +-
 ovn/controller/ovn-controller.c |   2 +-
 ovn/controller/pinctrl.c        |   2 +-
 ovn/lib/actions.c               |   6 +-
 ovn/lib/actions.h               | 141 ------------
 ovn/lib/automake.mk             |   3 -
 ovn/lib/expr.c                  |   4 +-
 ovn/lib/expr.h                  | 474 ----------------------------------------
 ovn/lib/lex.c                   |   2 +-
 ovn/lib/lex.h                   | 139 ------------
 ovn/northd/ovn-northd.c         |   2 +-
 tests/test-ovn.c                |   6 +-
 18 files changed, 775 insertions(+), 772 deletions(-)
 create mode 100644 include/ovn/actions.h
 create mode 100644 include/ovn/automake.mk
 create mode 100644 include/ovn/expr.h
 create mode 100644 include/ovn/lex.h
 delete mode 100644 ovn/lib/actions.h
 delete mode 100644 ovn/lib/expr.h
 delete mode 100644 ovn/lib/lex.h

diff --git a/include/automake.mk b/include/automake.mk
index 6a4cf86..37903fd 100644
--- a/include/automake.mk
+++ b/include/automake.mk
@@ -6,6 +6,7 @@ include/odp-netlink.h: 
datapath/linux/compat/include/linux/openvswitch.h \
 EXTRA_DIST += build-aux/extract-odp-netlink-h
 CLEANFILES += include/odp-netlink.h
 
+include include/ovn/automake.mk
 include include/openflow/automake.mk
 include include/openvswitch/automake.mk
 include include/sparse/automake.mk
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
new file mode 100644
index 0000000..114c71e
--- /dev/null
+++ b/include/ovn/actions.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_ACTIONS_H
+#define OVN_ACTIONS_H 1
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "compiler.h"
+#include "openvswitch/hmap.h"
+#include "openvswitch/dynamic-string.h"
+#include "util.h"
+
+struct expr;
+struct lexer;
+struct ofpbuf;
+struct shash;
+struct simap;
+
+#define MAX_OVN_GROUPS 65535
+
+struct group_table {
+    unsigned long *group_ids;  /* Used as a bitmap with value set
+                                * for allocated group ids in either
+                                * desired_groups or existing_groups. */
+    struct hmap desired_groups;
+    struct hmap existing_groups;
+};
+
+struct group_info {
+    struct hmap_node hmap_node;
+    struct ds group;
+    uint32_t group_id;
+};
+
+enum action_opcode {
+    /* "arp { ...actions... }".
+     *
+     * The actions, in OpenFlow 1.3 format, follow the action_header.
+     */
+    ACTION_OPCODE_ARP,
+
+    /* "put_arp(port, ip, mac)"
+     *
+     * Arguments are passed through the packet metadata and data, as follows:
+     *
+     *     MFF_REG0 = ip
+     *     MFF_LOG_INPORT = port
+     *     MFF_ETH_SRC = mac
+     */
+    ACTION_OPCODE_PUT_ARP,
+
+    /* "result = put_dhcp_opts(offer_ip, option, ...)".
+     *
+     * Arguments follow the action_header, in this format:
+     *   - A 32-bit or 64-bit OXM header designating the result field.
+     *   - A 32-bit integer specifying a bit offset within the result field.
+     *   - The 32-bit DHCP offer IP.
+     *   - Any number of DHCP options.
+     */
+    ACTION_OPCODE_PUT_DHCP_OPTS,
+
+    /* "na { ...actions... }".
+     *
+     * The actions, in OpenFlow 1.3 format, follow the action_header.
+     */
+    ACTION_OPCODE_NA,
+};
+
+/* Header. */
+struct action_header {
+    ovs_be32 opcode;            /* One of ACTION_OPCODE_* */
+    uint8_t pad[4];
+};
+BUILD_ASSERT_DECL(sizeof(struct action_header) == 8);
+
+struct action_params {
+    /* A table of "struct expr_symbol"s to support (as one would provide to
+     * expr_parse()). */
+    const struct shash *symtab;
+
+    /* hmap of 'struct dhcp_opts_map'  to support 'put_dhcp_opts' action */
+    const struct hmap *dhcp_opts;
+
+    /* Looks up logical port 'port_name'.  If found, stores its port number in
+     * '*portp' and returns true; otherwise, returns false. */
+    bool (*lookup_port)(const void *aux, const char *port_name,
+                        unsigned int *portp);
+    const void *aux;
+
+    /* A map from a port name to its connection tracking zone. */
+    const struct simap *ct_zones;
+
+    /* A struct to figure out the group_id for group actions. */
+    struct group_table *group_table;
+
+    /* OVN maps each logical flow table (ltable), one-to-one, onto a physical
+     * OpenFlow flow table (ptable).  A number of parameters describe this
+     * mapping and data related to flow tables:
+     *
+     *     - 'first_ptable' and 'n_tables' define the range of OpenFlow tables
+     *        to which the logical "next" action should be able to jump.
+     *        Logical table 0 maps to OpenFlow table 'first_ptable', logical
+     *        table 1 to 'first_ptable + 1', and so on.  If 'n_tables' is 0
+     *        then "next" is disallowed entirely.
+     *
+     *     - 'cur_ltable' is an offset from 'first_ptable' (e.g. 0 <=
+     *       cur_ltable < n_ptables) of the logical flow that contains the
+     *       actions.  If cur_ltable + 1 < n_tables, then this defines the
+     *       default table that "next" will jump to.
+     *
+     *     - 'output_ptable' should be the OpenFlow table to which the logical
+     *       "output" action will resubmit. */
+    uint8_t n_tables;           /* Number of flow tables. */
+    uint8_t first_ptable;       /* First OpenFlow table. */
+    uint8_t cur_ltable;         /* 0 <= cur_ltable < n_tables. */
+    uint8_t output_ptable;      /* OpenFlow table for 'output' to resubmit. */
+    uint8_t arp_ptable;         /* OpenFlow table for 'get_arp' to resubmit. */
+};
+
+char *actions_parse(struct lexer *, const struct action_params *,
+                    struct ofpbuf *ofpacts, struct expr **prereqsp)
+    OVS_WARN_UNUSED_RESULT;
+char *actions_parse_string(const char *s, const struct action_params *,
+                           struct ofpbuf *ofpacts, struct expr **prereqsp)
+    OVS_WARN_UNUSED_RESULT;
+
+#endif /* ovn/actions.h */
diff --git a/include/ovn/automake.mk b/include/ovn/automake.mk
new file mode 100644
index 0000000..d2924c2
--- /dev/null
+++ b/include/ovn/automake.mk
@@ -0,0 +1,5 @@
+ovnincludedir = $(includedir)/ovn
+ovninclude_HEADERS = \
+       include/ovn/actions.h \
+       include/ovn/expr.h \
+       include/ovn/lex.h
diff --git a/include/ovn/expr.h b/include/ovn/expr.h
new file mode 100644
index 0000000..d790c49
--- /dev/null
+++ b/include/ovn/expr.h
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2015, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_EXPR_H
+#define OVN_EXPR_H 1
+
+/* OVN matching expression tree
+ * ============================
+ *
+ * The data structures here form an abstract expression tree for matching
+ * expressions in OVN.
+ *
+ * The abstract syntax tree representation of a matching expression is one of:
+ *
+ *    - A Boolean literal ("true" or "false").
+ *
+ *    - A comparison of a field (or part of a field) against a constant
+ *      with one of the operators == != < <= > >=.
+ *
+ *    - The logical AND or OR of two or more matching expressions.
+ *
+ * Literals and comparisons are called "terminal" nodes, logical AND and OR
+ * nodes are "nonterminal" nodes.
+ *
+ * The syntax for expressions includes a few other concepts that are not part
+ * of the abstract syntax tree.  In these examples, x is a field, a, b, and c
+ * are constants, and e1 and e2 are arbitrary expressions:
+ *
+ *    - Logical NOT.  The parser implements NOT by inverting the sense of the
+ *      operand: !(x == a) becomes x != a, !(e1 && e2) becomes !e1 || !e2, and
+ *      so on.
+ *
+ *    - Set membership.  The parser translates x == {a, b, c} into
+ *      x == a || x == b || x == c.
+ *
+ *    - Reversed comparisons.  The parser translates a < x into x > a.
+ *
+ *    - Range expressions.  The parser translates a < x < b into
+ *      x > a && x < b.
+ */
+
+#include "classifier.h"
+#include "lex.h"
+#include "openvswitch/hmap.h"
+#include "openvswitch/list.h"
+#include "openvswitch/match.h"
+#include "openvswitch/meta-flow.h"
+
+struct ds;
+struct ofpbuf;
+struct shash;
+struct simap;
+
+/* "Measurement level" of a field.  See "Level of Measurement" in the large
+ * comment on struct expr_symbol below for more information. */
+enum expr_level {
+    EXPR_L_NOMINAL,
+
+    /* Boolean values are nominal, however because of their simple nature OVN
+     * can allow both equality and inequality tests on them. */
+    EXPR_L_BOOLEAN,
+
+    /* Ordinal values can at least be ordered on a scale.  OVN allows equality
+     * and inequality and relational tests on ordinal values.  These are the
+     * fields on which OVS allows bitwise matching. */
+    EXPR_L_ORDINAL
+};
+
+const char *expr_level_to_string(enum expr_level);
+
+/* A symbol.
+ *
+ *
+ * Name
+ * ====
+ *
+ * Every symbol must have a name.  To be useful, the name must satisfy the
+ * lexer's syntax for an identifier.
+ *
+ *
+ * Width
+ * =====
+ *
+ * Every symbol has a width.  For integer symbols, this is the number of bits
+ * in the value; for string symbols, this is 0.
+ *
+ *
+ * Types
+ * =====
+ *
+ * There are three kinds of symbols:
+ *
+ *   Fields:
+ *
+ *     One might, for example, define a field named "vlan.tci" to refer to
+ *     MFF_VLAN_TCI.  For integer fields, 'field' specifies the referent; for
+ *     string fields, 'field' is NULL.
+ *
+ *     'expansion' is NULL.
+ *
+ *     Integer fields can be nominal or ordinal (see below).  String fields are
+ *     always nominal.
+ *
+ *   Subfields:
+ *
+ *     'expansion' is a string that specifies a subfield of some larger field,
+ *     e.g. "vlan.tci[0..11]" for a field that represents a VLAN VID.
+ *
+ *     'field' is NULL.
+ *
+ *     Only ordinal fields (see below) may have subfields, and subfields are
+ *     always ordinal.
+ *
+ *   Predicates:
+ *
+ *     A predicate is an arbitrary Boolean expression that can be used in an
+ *     expression much like a 1-bit field.  'expansion' specifies the Boolean
+ *     expression, e.g. "ip4" might expand to "eth.type == 0x800".  The
+ *     expansion of a predicate might refer to other predicates, e.g. "icmp4"
+ *     might expand to "ip4 && ip4.proto == 1".
+ *
+ *     'field' is NULL.
+ *
+ *     A predicate whose expansion refers to any nominal field or predicate
+ *     (see below) is nominal; other predicates have Boolean level of
+ *     measurement.
+ *
+ *
+ * Level of Measurement
+ * ====================
+ *
+ * See http://en.wikipedia.org/wiki/Level_of_measurement for the statistical
+ * concept on which this classification is based.  There are three levels:
+ *
+ *   Ordinal:
+ *
+ *     In statistics, ordinal values can be ordered on a scale.  Here, we
+ *     consider a field (or subfield) to be ordinal if its bits can be examined
+ *     individually.  This is true for the OpenFlow fields that OpenFlow or
+ *     Open vSwitch makes "maskable".
+ *
+ *     OVN supports all the usual arithmetic relations (== != < <= > >=) on
+ *     ordinal fields and their subfields, because all of these can be
+ *     implemented as collections of bitwise tests.
+ *
+ *   Nominal:
+ *
+ *     In statistics, nominal values cannot be usefully compared except for
+ *     equality.  This is true of OpenFlow port numbers, Ethernet types, and IP
+ *     protocols are examples: all of these are just identifiers assigned
+ *     arbitrarily with no deeper meaning.  In OpenFlow and Open vSwitch, bits
+ *     in these fields generally aren't individually addressable.
+ *
+ *     OVN only supports arithmetic tests for equality on nominal fields,
+ *     because OpenFlow and Open vSwitch provide no way for a flow to
+ *     efficiently implement other comparisons on them.  (A test for inequality
+ *     can be sort of built out of two flows with different priorities, but OVN
+ *     matching expressions always generate flows with a single priority.)
+ *
+ *     String fields are always nominal.
+ *
+ *   Boolean:
+ *
+ *     A nominal field that has only two values, 0 and 1, is somewhat
+ *     exceptional, since it is easy to support both equality and inequality
+ *     tests on such a field: either one can be implemented as a test for 0 or
+ *     1.
+ *
+ *     Only predicates (see above) have a Boolean level of measurement.
+ *
+ *     This isn't a standard level of measurement.
+ *
+ *
+ * Prerequisites
+ * =============
+ *
+ * Any symbol can have prerequisites, which are specified as a string giving an
+ * additional expression that must be true whenever the symbol is referenced.
+ * For example, the "icmp4.type" symbol might have prerequisite "icmp4", which
+ * would cause an expression "icmp4.type == 0" to be interpreted as "icmp4.type
+ * == 0 && icmp4", which would in turn expand to "icmp4.type == 0 && eth.type
+ * == 0x800 && ip4.proto == 1" (assuming "icmp4" is a predicate defined as
+ * suggested under "Types" above).
+ *
+ *
+ * Crossproducting
+ * ===============
+ *
+ * Ordinarily OVN is willing to consider using any field as a dimension in the
+ * Open vSwitch "conjunctive match" extension (see ovs-ofctl(8)).  However,
+ * some fields can't actually be used that way because they are necessary as
+ * prerequisites.  For example, from an expression like "tcp.src == {1,2,3}
+ * && tcp.dst == {4,5,6}", OVN might naturally generate flows like this:
+ *
+ *     conj_id=1,actions=...
+ *     ip,actions=conjunction(1,1/3)
+ *     ip6,actions=conjunction(1,1/3)
+ *     tp_src=1,actions=conjunction(1,2/3)
+ *     tp_src=2,actions=conjunction(1,2/3)
+ *     tp_src=3,actions=conjunction(1,2/3)
+ *     tp_dst=4,actions=conjunction(1,3/3)
+ *     tp_dst=5,actions=conjunction(1,3/3)
+ *     tp_dst=6,actions=conjunction(1,3/3)
+ *
+ * but that's not valid because any flow that matches on tp_src or tp_dst must
+ * also match on either ip or ip6.  Thus, one would mark eth.type as "must
+ * crossproduct", to force generating flows like this:
+ *
+ *     conj_id=1,actions=...
+ *     ip,tp_src=1,actions=conjunction(1,1/2)
+ *     ip,tp_src=2,actions=conjunction(1,1/2)
+ *     ip,tp_src=3,actions=conjunction(1,1/2)
+ *     ip6,tp_src=1,actions=conjunction(1,1/2)
+ *     ip6,tp_src=2,actions=conjunction(1,1/2)
+ *     ip6,tp_src=3,actions=conjunction(1,1/2)
+ *     ip,tp_dst=4,actions=conjunction(1,2/2)
+ *     ip,tp_dst=5,actions=conjunction(1,2/2)
+ *     ip,tp_dst=6,actions=conjunction(1,2/2)
+ *     ip6,tp_dst=4,actions=conjunction(1,2/2)
+ *     ip6,tp_dst=5,actions=conjunction(1,2/2)
+ *     ip6,tp_dst=6,actions=conjunction(1,2/2)
+ *
+ * which are acceptable.
+ */
+struct expr_symbol {
+    char *name;
+    int width;
+
+    const struct mf_field *field;
+    char *expansion;
+
+    enum expr_level level;
+
+    char *prereqs;
+    bool must_crossproduct;
+};
+
+/* A reference to a symbol or a subfield of a symbol.
+ *
+ * For string fields, ofs and n_bits are 0. */
+struct expr_field {
+    const struct expr_symbol *symbol; /* The symbol. */
+    int ofs;                          /* Starting bit offset. */
+    int n_bits;                       /* Number of bits. */
+};
+
+struct expr_symbol *expr_symtab_add_field(struct shash *symtab,
+                                          const char *name, enum mf_field_id,
+                                          const char *prereqs,
+                                          bool must_crossproduct);
+struct expr_symbol *expr_symtab_add_subfield(struct shash *symtab,
+                                             const char *name,
+                                             const char *prereqs,
+                                             const char *subfield);
+struct expr_symbol *expr_symtab_add_string(struct shash *symtab,
+                                           const char *name, enum mf_field_id,
+                                           const char *prereqs);
+struct expr_symbol *expr_symtab_add_predicate(struct shash *symtab,
+                                              const char *name,
+                                              const char *expansion);
+void expr_symtab_destroy(struct shash *symtab);
+
+/* Expression type. */
+enum expr_type {
+    EXPR_T_CMP,                 /* Compare symbol with constant. */
+    EXPR_T_AND,                 /* Logical AND of 2 or more subexpressions. */
+    EXPR_T_OR,                  /* Logical OR of 2 or more subexpressions. */
+    EXPR_T_BOOLEAN,             /* True or false constant. */
+};
+
+/* Relational operator. */
+enum expr_relop {
+    EXPR_R_EQ,                  /* == */
+    EXPR_R_NE,                  /* != */
+    EXPR_R_LT,                  /* < */
+    EXPR_R_LE,                  /* <= */
+    EXPR_R_GT,                  /* > */
+    EXPR_R_GE,                  /* >= */
+};
+const char *expr_relop_to_string(enum expr_relop);
+bool expr_relop_from_token(enum lex_type type, enum expr_relop *relop);
+
+/* An abstract syntax tree for a matching expression.
+ *
+ * The expression code maintains and relies on a few important invariants:
+ *
+ *     - An EXPR_T_AND or EXPR_T_OR node never has a child of the same type.
+ *       (Any such children could be merged into their parent.)  A node may
+ *       have grandchildren of its own type.
+ *
+ *       As a consequence, every nonterminal node at the same distance from the
+ *       root has the same type.
+ *
+ *     - EXPR_T_AND and EXPR_T_OR nodes must have at least two children.
+ *
+ *     - An EXPR_T_CMP node always has a nonzero mask, and never has a 1-bit
+ *       in its value in a position where the mask is a 0-bit.
+ *
+ * The expr_honors_invariants() function can check invariants. */
+struct expr {
+    struct ovs_list node;       /* In parent EXPR_T_AND or EXPR_T_OR if any. */
+    enum expr_type type;        /* Expression type. */
+
+    union {
+        /* EXPR_T_CMP.
+         *
+         * The symbol is on the left, e.g. "field < constant". */
+        struct {
+            const struct expr_symbol *symbol;
+            enum expr_relop relop;
+
+            union {
+                char *string;
+                struct {
+                    union mf_subvalue value;
+                    union mf_subvalue mask;
+                };
+            };
+        } cmp;
+
+        /* EXPR_T_AND, EXPR_T_OR. */
+        struct ovs_list andor;
+
+        /* EXPR_T_BOOLEAN. */
+        bool boolean;
+    };
+};
+
+struct expr *expr_create_boolean(bool b);
+struct expr *expr_create_andor(enum expr_type);
+struct expr *expr_combine(enum expr_type, struct expr *a, struct expr *b);
+
+static inline struct expr *
+expr_from_node(const struct ovs_list *node)
+{
+    return CONTAINER_OF(node, struct expr, node);
+}
+
+void expr_format(const struct expr *, struct ds *);
+void expr_print(const struct expr *);
+struct expr *expr_parse(struct lexer *, const struct shash *symtab,
+                        const struct shash *macros,
+                        char **errorp);
+struct expr *expr_parse_string(const char *, const struct shash *symtab,
+                               const struct shash *macros,
+                               char **errorp);
+
+struct expr *expr_clone(struct expr *);
+void expr_destroy(struct expr *);
+
+struct expr *expr_annotate(struct expr *, const struct shash *symtab,
+                           char **errorp);
+struct expr *expr_simplify(struct expr *);
+struct expr *expr_normalize(struct expr *);
+
+bool expr_honors_invariants(const struct expr *);
+bool expr_is_simplified(const struct expr *);
+bool expr_is_normalized(const struct expr *);
+
+/* Converting expressions to OpenFlow flows. */
+
+/* An OpenFlow match generated from a Boolean expression.  See
+ * expr_to_matches() for more information. */
+struct expr_match {
+    struct hmap_node hmap_node;
+    struct match match;
+    struct cls_conjunction *conjunctions;
+    size_t n, allocated;
+};
+
+uint32_t expr_to_matches(const struct expr *,
+                         bool (*lookup_port)(const void *aux,
+                                             const char *port_name,
+                                             unsigned int *portp),
+                         const void *aux,
+                         struct hmap *matches);
+void expr_matches_destroy(struct hmap *matches);
+void expr_matches_print(const struct hmap *matches, FILE *);
+
+/* Action parsing helper. */
+
+char *expr_parse_assignment(struct lexer *lexer, struct expr_field *dst,
+                            const struct shash *symtab,
+                            bool (*lookup_port)(const void *aux,
+                                                const char *port_name,
+                                                unsigned int *portp),
+                            const void *aux,
+                            struct ofpbuf *ofpacts, struct expr **prereqsp)
+    OVS_WARN_UNUSED_RESULT;
+char *expr_parse_exchange(struct lexer *lexer, struct expr_field *dst,
+                          const struct shash *symtab,
+                          bool (*lookup_port)(const void *aux,
+                                              const char *port_name,
+                                              unsigned int *portp),
+                          const void *aux,
+                          struct ofpbuf *ofpacts, struct expr **prereqsp)
+    OVS_WARN_UNUSED_RESULT;
+char *expr_parse_field(struct lexer *lexer, const struct shash *symtab,
+                       struct expr_field *field)
+    OVS_WARN_UNUSED_RESULT;
+char *expr_expand_field(struct lexer *lexer, const struct shash *symtab,
+                        const struct expr_field *orig_field,
+                        int n_bits, bool rw,
+                        struct mf_subfield *sf, struct expr **prereqsp)
+    OVS_WARN_UNUSED_RESULT;
+
+/* Type of a "union expr_constant" or "struct expr_constant_set". */
+enum expr_constant_type {
+    EXPR_C_INTEGER,
+    EXPR_C_STRING
+};
+
+/* A string or integer constant (one must know which from context). */
+union expr_constant {
+    /* Integer constant.
+     *
+     * The width of a constant isn't always clear, e.g. if you write "1",
+     * there's no way to tell whether you mean for that to be a 1-bit constant
+     * or a 128-bit constant or somewhere in between. */
+    struct {
+        union mf_subvalue value;
+        union mf_subvalue mask; /* Only initialized if 'masked'. */
+        bool masked;
+
+        enum lex_format format; /* From the constant's lex_token. */
+    };
+
+    /* Null-terminated string constant. */
+    char *string;
+};
+
+/* A collection of "union expr_constant"s of the same type. */
+struct expr_constant_set {
+    union expr_constant *values;  /* Constants. */
+    size_t n_values;              /* Number of constants. */
+    enum expr_constant_type type; /* Type of the constants. */
+    bool in_curlies;              /* Whether the constants were in {}. */
+};
+
+char *expr_parse_constant_set(struct lexer *, const struct shash *symtab,
+                              struct expr_constant_set *cs)
+    OVS_WARN_UNUSED_RESULT;
+void expr_constant_set_destroy(struct expr_constant_set *cs);
+
+
+/* Address sets, aka "macros".
+ *
+ * Instead of referring to a set of value as:
+ *    {addr1, addr2, ..., addrN}
+ * You can register a set of values and refer to them as:
+ *    $name
+ * The macros should all have integer/masked-integer values.
+ * The values that don't qualify are ignored.
+ */
+
+void expr_macros_add(struct shash *macros, const char *name,
+                     const char * const *values, size_t n_values);
+void expr_macros_remove(struct shash *macros, const char *name);
+void expr_macros_destroy(struct shash *macros);
+
+#endif /* ovn/expr.h */
diff --git a/include/ovn/lex.h b/include/ovn/lex.h
new file mode 100644
index 0000000..4de48c7
--- /dev/null
+++ b/include/ovn/lex.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, 2016 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OVN_LEX_H
+#define OVN_LEX_H 1
+
+/* OVN lexical analyzer
+ * ====================
+ *
+ * This is a simple lexical analyzer (or tokenizer) for OVN match expressions
+ * and ACLs. */
+
+#include "openvswitch/meta-flow.h"
+
+struct ds;
+
+/* Token type. */
+enum lex_type {
+    LEX_T_END,                  /* end of input */
+
+    /* Tokens with auxiliary data. */
+    LEX_T_ID,                   /* foo */
+    LEX_T_STRING,               /* "foo" */
+    LEX_T_INTEGER,              /* 12345 or 1.2.3.4 or ::1 or 01:02:03:04:05 */
+    LEX_T_MASKED_INTEGER,       /* 12345/10 or 1.2.0.0/16 or ::2/127 or... */
+    LEX_T_MACRO,                /* $NAME */
+    LEX_T_ERROR,                /* invalid input */
+
+    /* Bare tokens. */
+    LEX_T_LPAREN,               /* ( */
+    LEX_T_RPAREN,               /* ) */
+    LEX_T_LCURLY,               /* { */
+    LEX_T_RCURLY,               /* } */
+    LEX_T_LSQUARE,              /* [ */
+    LEX_T_RSQUARE,              /* ] */
+    LEX_T_EQ,                   /* == */
+    LEX_T_NE,                   /* != */
+    LEX_T_LT,                   /* < */
+    LEX_T_LE,                   /* <= */
+    LEX_T_GT,                   /* > */
+    LEX_T_GE,                   /* >= */
+    LEX_T_LOG_NOT,              /* ! */
+    LEX_T_LOG_AND,              /* && */
+    LEX_T_LOG_OR,               /* || */
+    LEX_T_ELLIPSIS,             /* .. */
+    LEX_T_COMMA,                /* , */
+    LEX_T_SEMICOLON,            /* ; */
+    LEX_T_EQUALS,               /* = */
+    LEX_T_EXCHANGE,             /* <-> */
+    LEX_T_DECREMENT,            /* -- */
+    LEX_T_COLON,                /* : */
+};
+
+/* Subtype for LEX_T_INTEGER and LEX_T_MASKED_INTEGER tokens.
+ *
+ * These do not change the semantics of a token; instead, they determine the
+ * format used when a token is serialized back to a text form.  That's
+ * important because 3232268289 is meaningless to a human whereas 192.168.128.1
+ * has some actual significance. */
+enum lex_format {
+    LEX_F_DECIMAL,
+    LEX_F_HEXADECIMAL,
+    LEX_F_IPV4,
+    LEX_F_IPV6,
+    LEX_F_ETHERNET,
+};
+const char *lex_format_to_string(enum lex_format);
+
+/* A token. */
+struct lex_token {
+    /* One of LEX_*. */
+    enum lex_type type;
+
+    /* Meaningful for LEX_T_ID, LEX_T_STRING, LEX_T_ERROR, LEX_T_MACRO only.
+     * For these token types, 's' may point to 'buffer'; otherwise, it points
+     * to malloc()ed memory owned by the token.
+     *
+     * Must be NULL for other token types.
+     *
+     * For LEX_T_MACRO, 's' does not include the leading $. */
+    char *s;
+
+    /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER only. */
+    enum lex_format format;
+
+    union {
+        /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER only. */
+        struct {
+            union mf_subvalue value; /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER. */
+            union mf_subvalue mask;  /* LEX_T_MASKED_INTEGER only. */
+        };
+
+        /* LEX_T_ID, LEX_T_STRING, LEX_T_ERROR, LEX_T_MACRO only. */
+        char buffer[256];
+    };
+};
+
+void lex_token_init(struct lex_token *);
+void lex_token_destroy(struct lex_token *);
+void lex_token_swap(struct lex_token *, struct lex_token *);
+void lex_token_strcpy(struct lex_token *, const char *s, size_t length);
+void lex_token_strset(struct lex_token *, char *s);
+void lex_token_vsprintf(struct lex_token *, const char *format, va_list args);
+
+void lex_token_format(const struct lex_token *, struct ds *);
+const char *lex_token_parse(struct lex_token *, const char *input,
+                            const char **startp);
+
+/* A lexical analyzer. */
+struct lexer {
+    const char *input;          /* Remaining input (not owned by lexer). */
+    const char *start;          /* Start of current token in 'input'. */
+    struct lex_token token;     /* Current token (owned by lexer). */
+};
+
+void lexer_init(struct lexer *, const char *input);
+void lexer_destroy(struct lexer *);
+
+enum lex_type lexer_get(struct lexer *);
+enum lex_type lexer_lookahead(const struct lexer *);
+bool lexer_match(struct lexer *, enum lex_type);
+bool lexer_match_id(struct lexer *, const char *id);
+bool lexer_is_int(const struct lexer *);
+bool lexer_get_int(struct lexer *, int *value);
+
+#endif /* ovn/lex.h */
diff --git a/ovn/controller/lflow.c b/ovn/controller/lflow.c
index 42c9055..a4f3322 100644
--- a/ovn/controller/lflow.c
+++ b/ovn/controller/lflow.c
@@ -22,8 +22,8 @@
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 #include "ovn-controller.h"
-#include "ovn/lib/actions.h"
-#include "ovn/lib/expr.h"
+#include "ovn/actions.h"
+#include "ovn/expr.h"
 #include "ovn/lib/ovn-dhcp.h"
 #include "ovn/lib/ovn-sb-idl.h"
 #include "packets.h"
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
index f0451b7..6274888 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -34,7 +34,7 @@
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
 #include "ovn-controller.h"
-#include "ovn/lib/actions.h"
+#include "ovn/actions.h"
 #include "poll-loop.h"
 #include "physical.h"
 #include "rconn.h"
diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c
index 4d9490a..95d3ff3 100644
--- a/ovn/controller/ovn-controller.c
+++ b/ovn/controller/ovn-controller.c
@@ -39,7 +39,7 @@
 #include "ofctrl.h"
 #include "openvswitch/vconn.h"
 #include "openvswitch/vlog.h"
-#include "ovn/lib/actions.h"
+#include "ovn/actions.h"
 #include "ovn/lib/ovn-sb-idl.h"
 #include "ovn/lib/ovn-util.h"
 #include "patch.h"
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index 0ae6501..416dad6 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -35,7 +35,7 @@
 
 #include "lib/dhcp.h"
 #include "ovn-controller.h"
-#include "ovn/lib/actions.h"
+#include "ovn/actions.h"
 #include "ovn/lib/logical-fields.h"
 #include "ovn/lib/ovn-util.h"
 #include "poll-loop.h"
diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
index 6e2bf93..fd5a867 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -17,20 +17,20 @@
 #include <config.h>
 #include <stdarg.h>
 #include <stdbool.h>
-#include "actions.h"
 #include "bitmap.h"
 #include "byte-order.h"
 #include "compiler.h"
 #include "ovn-dhcp.h"
-#include "expr.h"
 #include "hash.h"
 #include "openvswitch/hmap.h"
-#include "lex.h"
 #include "logical-fields.h"
 #include "nx-match.h"
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/ofpbuf.h"
+#include "ovn/actions.h"
+#include "ovn/expr.h"
+#include "ovn/lex.h"
 #include "packets.h"
 #include "openvswitch/shash.h"
 #include "simap.h"
diff --git a/ovn/lib/actions.h b/ovn/lib/actions.h
deleted file mode 100644
index 114c71e..0000000
--- a/ovn/lib/actions.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2015, 2016 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OVN_ACTIONS_H
-#define OVN_ACTIONS_H 1
-
-#include <stdbool.h>
-#include <stdint.h>
-#include "compiler.h"
-#include "openvswitch/hmap.h"
-#include "openvswitch/dynamic-string.h"
-#include "util.h"
-
-struct expr;
-struct lexer;
-struct ofpbuf;
-struct shash;
-struct simap;
-
-#define MAX_OVN_GROUPS 65535
-
-struct group_table {
-    unsigned long *group_ids;  /* Used as a bitmap with value set
-                                * for allocated group ids in either
-                                * desired_groups or existing_groups. */
-    struct hmap desired_groups;
-    struct hmap existing_groups;
-};
-
-struct group_info {
-    struct hmap_node hmap_node;
-    struct ds group;
-    uint32_t group_id;
-};
-
-enum action_opcode {
-    /* "arp { ...actions... }".
-     *
-     * The actions, in OpenFlow 1.3 format, follow the action_header.
-     */
-    ACTION_OPCODE_ARP,
-
-    /* "put_arp(port, ip, mac)"
-     *
-     * Arguments are passed through the packet metadata and data, as follows:
-     *
-     *     MFF_REG0 = ip
-     *     MFF_LOG_INPORT = port
-     *     MFF_ETH_SRC = mac
-     */
-    ACTION_OPCODE_PUT_ARP,
-
-    /* "result = put_dhcp_opts(offer_ip, option, ...)".
-     *
-     * Arguments follow the action_header, in this format:
-     *   - A 32-bit or 64-bit OXM header designating the result field.
-     *   - A 32-bit integer specifying a bit offset within the result field.
-     *   - The 32-bit DHCP offer IP.
-     *   - Any number of DHCP options.
-     */
-    ACTION_OPCODE_PUT_DHCP_OPTS,
-
-    /* "na { ...actions... }".
-     *
-     * The actions, in OpenFlow 1.3 format, follow the action_header.
-     */
-    ACTION_OPCODE_NA,
-};
-
-/* Header. */
-struct action_header {
-    ovs_be32 opcode;            /* One of ACTION_OPCODE_* */
-    uint8_t pad[4];
-};
-BUILD_ASSERT_DECL(sizeof(struct action_header) == 8);
-
-struct action_params {
-    /* A table of "struct expr_symbol"s to support (as one would provide to
-     * expr_parse()). */
-    const struct shash *symtab;
-
-    /* hmap of 'struct dhcp_opts_map'  to support 'put_dhcp_opts' action */
-    const struct hmap *dhcp_opts;
-
-    /* Looks up logical port 'port_name'.  If found, stores its port number in
-     * '*portp' and returns true; otherwise, returns false. */
-    bool (*lookup_port)(const void *aux, const char *port_name,
-                        unsigned int *portp);
-    const void *aux;
-
-    /* A map from a port name to its connection tracking zone. */
-    const struct simap *ct_zones;
-
-    /* A struct to figure out the group_id for group actions. */
-    struct group_table *group_table;
-
-    /* OVN maps each logical flow table (ltable), one-to-one, onto a physical
-     * OpenFlow flow table (ptable).  A number of parameters describe this
-     * mapping and data related to flow tables:
-     *
-     *     - 'first_ptable' and 'n_tables' define the range of OpenFlow tables
-     *        to which the logical "next" action should be able to jump.
-     *        Logical table 0 maps to OpenFlow table 'first_ptable', logical
-     *        table 1 to 'first_ptable + 1', and so on.  If 'n_tables' is 0
-     *        then "next" is disallowed entirely.
-     *
-     *     - 'cur_ltable' is an offset from 'first_ptable' (e.g. 0 <=
-     *       cur_ltable < n_ptables) of the logical flow that contains the
-     *       actions.  If cur_ltable + 1 < n_tables, then this defines the
-     *       default table that "next" will jump to.
-     *
-     *     - 'output_ptable' should be the OpenFlow table to which the logical
-     *       "output" action will resubmit. */
-    uint8_t n_tables;           /* Number of flow tables. */
-    uint8_t first_ptable;       /* First OpenFlow table. */
-    uint8_t cur_ltable;         /* 0 <= cur_ltable < n_tables. */
-    uint8_t output_ptable;      /* OpenFlow table for 'output' to resubmit. */
-    uint8_t arp_ptable;         /* OpenFlow table for 'get_arp' to resubmit. */
-};
-
-char *actions_parse(struct lexer *, const struct action_params *,
-                    struct ofpbuf *ofpacts, struct expr **prereqsp)
-    OVS_WARN_UNUSED_RESULT;
-char *actions_parse_string(const char *s, const struct action_params *,
-                           struct ofpbuf *ofpacts, struct expr **prereqsp)
-    OVS_WARN_UNUSED_RESULT;
-
-#endif /* ovn/actions.h */
diff --git a/ovn/lib/automake.mk b/ovn/lib/automake.mk
index 4f8cd05..4e9daf5 100644
--- a/ovn/lib/automake.mk
+++ b/ovn/lib/automake.mk
@@ -5,11 +5,8 @@ ovn_lib_libovn_la_LDFLAGS = \
         $(AM_LDFLAGS)
 ovn_lib_libovn_la_SOURCES = \
        ovn/lib/actions.c \
-       ovn/lib/actions.h \
        ovn/lib/expr.c \
-       ovn/lib/expr.h \
        ovn/lib/lex.c \
-       ovn/lib/lex.h \
        ovn/lib/ovn-dhcp.h \
        ovn/lib/ovn-util.c \
        ovn/lib/ovn-util.h \
diff --git a/ovn/lib/expr.c b/ovn/lib/expr.c
index 1c38b99..288aae2 100644
--- a/ovn/lib/expr.c
+++ b/ovn/lib/expr.c
@@ -16,15 +16,15 @@
 
 #include <config.h>
 #include "byte-order.h"
-#include "expr.h"
 #include "openvswitch/json.h"
-#include "lex.h"
 #include "logical-fields.h"
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/match.h"
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/vlog.h"
 #include "openvswitch/shash.h"
+#include "ovn/expr.h"
+#include "ovn/lex.h"
 #include "simap.h"
 #include "sset.h"
 #include "util.h"
diff --git a/ovn/lib/expr.h b/ovn/lib/expr.h
deleted file mode 100644
index d790c49..0000000
--- a/ovn/lib/expr.h
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (c) 2015, 2016 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OVN_EXPR_H
-#define OVN_EXPR_H 1
-
-/* OVN matching expression tree
- * ============================
- *
- * The data structures here form an abstract expression tree for matching
- * expressions in OVN.
- *
- * The abstract syntax tree representation of a matching expression is one of:
- *
- *    - A Boolean literal ("true" or "false").
- *
- *    - A comparison of a field (or part of a field) against a constant
- *      with one of the operators == != < <= > >=.
- *
- *    - The logical AND or OR of two or more matching expressions.
- *
- * Literals and comparisons are called "terminal" nodes, logical AND and OR
- * nodes are "nonterminal" nodes.
- *
- * The syntax for expressions includes a few other concepts that are not part
- * of the abstract syntax tree.  In these examples, x is a field, a, b, and c
- * are constants, and e1 and e2 are arbitrary expressions:
- *
- *    - Logical NOT.  The parser implements NOT by inverting the sense of the
- *      operand: !(x == a) becomes x != a, !(e1 && e2) becomes !e1 || !e2, and
- *      so on.
- *
- *    - Set membership.  The parser translates x == {a, b, c} into
- *      x == a || x == b || x == c.
- *
- *    - Reversed comparisons.  The parser translates a < x into x > a.
- *
- *    - Range expressions.  The parser translates a < x < b into
- *      x > a && x < b.
- */
-
-#include "classifier.h"
-#include "lex.h"
-#include "openvswitch/hmap.h"
-#include "openvswitch/list.h"
-#include "openvswitch/match.h"
-#include "openvswitch/meta-flow.h"
-
-struct ds;
-struct ofpbuf;
-struct shash;
-struct simap;
-
-/* "Measurement level" of a field.  See "Level of Measurement" in the large
- * comment on struct expr_symbol below for more information. */
-enum expr_level {
-    EXPR_L_NOMINAL,
-
-    /* Boolean values are nominal, however because of their simple nature OVN
-     * can allow both equality and inequality tests on them. */
-    EXPR_L_BOOLEAN,
-
-    /* Ordinal values can at least be ordered on a scale.  OVN allows equality
-     * and inequality and relational tests on ordinal values.  These are the
-     * fields on which OVS allows bitwise matching. */
-    EXPR_L_ORDINAL
-};
-
-const char *expr_level_to_string(enum expr_level);
-
-/* A symbol.
- *
- *
- * Name
- * ====
- *
- * Every symbol must have a name.  To be useful, the name must satisfy the
- * lexer's syntax for an identifier.
- *
- *
- * Width
- * =====
- *
- * Every symbol has a width.  For integer symbols, this is the number of bits
- * in the value; for string symbols, this is 0.
- *
- *
- * Types
- * =====
- *
- * There are three kinds of symbols:
- *
- *   Fields:
- *
- *     One might, for example, define a field named "vlan.tci" to refer to
- *     MFF_VLAN_TCI.  For integer fields, 'field' specifies the referent; for
- *     string fields, 'field' is NULL.
- *
- *     'expansion' is NULL.
- *
- *     Integer fields can be nominal or ordinal (see below).  String fields are
- *     always nominal.
- *
- *   Subfields:
- *
- *     'expansion' is a string that specifies a subfield of some larger field,
- *     e.g. "vlan.tci[0..11]" for a field that represents a VLAN VID.
- *
- *     'field' is NULL.
- *
- *     Only ordinal fields (see below) may have subfields, and subfields are
- *     always ordinal.
- *
- *   Predicates:
- *
- *     A predicate is an arbitrary Boolean expression that can be used in an
- *     expression much like a 1-bit field.  'expansion' specifies the Boolean
- *     expression, e.g. "ip4" might expand to "eth.type == 0x800".  The
- *     expansion of a predicate might refer to other predicates, e.g. "icmp4"
- *     might expand to "ip4 && ip4.proto == 1".
- *
- *     'field' is NULL.
- *
- *     A predicate whose expansion refers to any nominal field or predicate
- *     (see below) is nominal; other predicates have Boolean level of
- *     measurement.
- *
- *
- * Level of Measurement
- * ====================
- *
- * See http://en.wikipedia.org/wiki/Level_of_measurement for the statistical
- * concept on which this classification is based.  There are three levels:
- *
- *   Ordinal:
- *
- *     In statistics, ordinal values can be ordered on a scale.  Here, we
- *     consider a field (or subfield) to be ordinal if its bits can be examined
- *     individually.  This is true for the OpenFlow fields that OpenFlow or
- *     Open vSwitch makes "maskable".
- *
- *     OVN supports all the usual arithmetic relations (== != < <= > >=) on
- *     ordinal fields and their subfields, because all of these can be
- *     implemented as collections of bitwise tests.
- *
- *   Nominal:
- *
- *     In statistics, nominal values cannot be usefully compared except for
- *     equality.  This is true of OpenFlow port numbers, Ethernet types, and IP
- *     protocols are examples: all of these are just identifiers assigned
- *     arbitrarily with no deeper meaning.  In OpenFlow and Open vSwitch, bits
- *     in these fields generally aren't individually addressable.
- *
- *     OVN only supports arithmetic tests for equality on nominal fields,
- *     because OpenFlow and Open vSwitch provide no way for a flow to
- *     efficiently implement other comparisons on them.  (A test for inequality
- *     can be sort of built out of two flows with different priorities, but OVN
- *     matching expressions always generate flows with a single priority.)
- *
- *     String fields are always nominal.
- *
- *   Boolean:
- *
- *     A nominal field that has only two values, 0 and 1, is somewhat
- *     exceptional, since it is easy to support both equality and inequality
- *     tests on such a field: either one can be implemented as a test for 0 or
- *     1.
- *
- *     Only predicates (see above) have a Boolean level of measurement.
- *
- *     This isn't a standard level of measurement.
- *
- *
- * Prerequisites
- * =============
- *
- * Any symbol can have prerequisites, which are specified as a string giving an
- * additional expression that must be true whenever the symbol is referenced.
- * For example, the "icmp4.type" symbol might have prerequisite "icmp4", which
- * would cause an expression "icmp4.type == 0" to be interpreted as "icmp4.type
- * == 0 && icmp4", which would in turn expand to "icmp4.type == 0 && eth.type
- * == 0x800 && ip4.proto == 1" (assuming "icmp4" is a predicate defined as
- * suggested under "Types" above).
- *
- *
- * Crossproducting
- * ===============
- *
- * Ordinarily OVN is willing to consider using any field as a dimension in the
- * Open vSwitch "conjunctive match" extension (see ovs-ofctl(8)).  However,
- * some fields can't actually be used that way because they are necessary as
- * prerequisites.  For example, from an expression like "tcp.src == {1,2,3}
- * && tcp.dst == {4,5,6}", OVN might naturally generate flows like this:
- *
- *     conj_id=1,actions=...
- *     ip,actions=conjunction(1,1/3)
- *     ip6,actions=conjunction(1,1/3)
- *     tp_src=1,actions=conjunction(1,2/3)
- *     tp_src=2,actions=conjunction(1,2/3)
- *     tp_src=3,actions=conjunction(1,2/3)
- *     tp_dst=4,actions=conjunction(1,3/3)
- *     tp_dst=5,actions=conjunction(1,3/3)
- *     tp_dst=6,actions=conjunction(1,3/3)
- *
- * but that's not valid because any flow that matches on tp_src or tp_dst must
- * also match on either ip or ip6.  Thus, one would mark eth.type as "must
- * crossproduct", to force generating flows like this:
- *
- *     conj_id=1,actions=...
- *     ip,tp_src=1,actions=conjunction(1,1/2)
- *     ip,tp_src=2,actions=conjunction(1,1/2)
- *     ip,tp_src=3,actions=conjunction(1,1/2)
- *     ip6,tp_src=1,actions=conjunction(1,1/2)
- *     ip6,tp_src=2,actions=conjunction(1,1/2)
- *     ip6,tp_src=3,actions=conjunction(1,1/2)
- *     ip,tp_dst=4,actions=conjunction(1,2/2)
- *     ip,tp_dst=5,actions=conjunction(1,2/2)
- *     ip,tp_dst=6,actions=conjunction(1,2/2)
- *     ip6,tp_dst=4,actions=conjunction(1,2/2)
- *     ip6,tp_dst=5,actions=conjunction(1,2/2)
- *     ip6,tp_dst=6,actions=conjunction(1,2/2)
- *
- * which are acceptable.
- */
-struct expr_symbol {
-    char *name;
-    int width;
-
-    const struct mf_field *field;
-    char *expansion;
-
-    enum expr_level level;
-
-    char *prereqs;
-    bool must_crossproduct;
-};
-
-/* A reference to a symbol or a subfield of a symbol.
- *
- * For string fields, ofs and n_bits are 0. */
-struct expr_field {
-    const struct expr_symbol *symbol; /* The symbol. */
-    int ofs;                          /* Starting bit offset. */
-    int n_bits;                       /* Number of bits. */
-};
-
-struct expr_symbol *expr_symtab_add_field(struct shash *symtab,
-                                          const char *name, enum mf_field_id,
-                                          const char *prereqs,
-                                          bool must_crossproduct);
-struct expr_symbol *expr_symtab_add_subfield(struct shash *symtab,
-                                             const char *name,
-                                             const char *prereqs,
-                                             const char *subfield);
-struct expr_symbol *expr_symtab_add_string(struct shash *symtab,
-                                           const char *name, enum mf_field_id,
-                                           const char *prereqs);
-struct expr_symbol *expr_symtab_add_predicate(struct shash *symtab,
-                                              const char *name,
-                                              const char *expansion);
-void expr_symtab_destroy(struct shash *symtab);
-
-/* Expression type. */
-enum expr_type {
-    EXPR_T_CMP,                 /* Compare symbol with constant. */
-    EXPR_T_AND,                 /* Logical AND of 2 or more subexpressions. */
-    EXPR_T_OR,                  /* Logical OR of 2 or more subexpressions. */
-    EXPR_T_BOOLEAN,             /* True or false constant. */
-};
-
-/* Relational operator. */
-enum expr_relop {
-    EXPR_R_EQ,                  /* == */
-    EXPR_R_NE,                  /* != */
-    EXPR_R_LT,                  /* < */
-    EXPR_R_LE,                  /* <= */
-    EXPR_R_GT,                  /* > */
-    EXPR_R_GE,                  /* >= */
-};
-const char *expr_relop_to_string(enum expr_relop);
-bool expr_relop_from_token(enum lex_type type, enum expr_relop *relop);
-
-/* An abstract syntax tree for a matching expression.
- *
- * The expression code maintains and relies on a few important invariants:
- *
- *     - An EXPR_T_AND or EXPR_T_OR node never has a child of the same type.
- *       (Any such children could be merged into their parent.)  A node may
- *       have grandchildren of its own type.
- *
- *       As a consequence, every nonterminal node at the same distance from the
- *       root has the same type.
- *
- *     - EXPR_T_AND and EXPR_T_OR nodes must have at least two children.
- *
- *     - An EXPR_T_CMP node always has a nonzero mask, and never has a 1-bit
- *       in its value in a position where the mask is a 0-bit.
- *
- * The expr_honors_invariants() function can check invariants. */
-struct expr {
-    struct ovs_list node;       /* In parent EXPR_T_AND or EXPR_T_OR if any. */
-    enum expr_type type;        /* Expression type. */
-
-    union {
-        /* EXPR_T_CMP.
-         *
-         * The symbol is on the left, e.g. "field < constant". */
-        struct {
-            const struct expr_symbol *symbol;
-            enum expr_relop relop;
-
-            union {
-                char *string;
-                struct {
-                    union mf_subvalue value;
-                    union mf_subvalue mask;
-                };
-            };
-        } cmp;
-
-        /* EXPR_T_AND, EXPR_T_OR. */
-        struct ovs_list andor;
-
-        /* EXPR_T_BOOLEAN. */
-        bool boolean;
-    };
-};
-
-struct expr *expr_create_boolean(bool b);
-struct expr *expr_create_andor(enum expr_type);
-struct expr *expr_combine(enum expr_type, struct expr *a, struct expr *b);
-
-static inline struct expr *
-expr_from_node(const struct ovs_list *node)
-{
-    return CONTAINER_OF(node, struct expr, node);
-}
-
-void expr_format(const struct expr *, struct ds *);
-void expr_print(const struct expr *);
-struct expr *expr_parse(struct lexer *, const struct shash *symtab,
-                        const struct shash *macros,
-                        char **errorp);
-struct expr *expr_parse_string(const char *, const struct shash *symtab,
-                               const struct shash *macros,
-                               char **errorp);
-
-struct expr *expr_clone(struct expr *);
-void expr_destroy(struct expr *);
-
-struct expr *expr_annotate(struct expr *, const struct shash *symtab,
-                           char **errorp);
-struct expr *expr_simplify(struct expr *);
-struct expr *expr_normalize(struct expr *);
-
-bool expr_honors_invariants(const struct expr *);
-bool expr_is_simplified(const struct expr *);
-bool expr_is_normalized(const struct expr *);
-
-/* Converting expressions to OpenFlow flows. */
-
-/* An OpenFlow match generated from a Boolean expression.  See
- * expr_to_matches() for more information. */
-struct expr_match {
-    struct hmap_node hmap_node;
-    struct match match;
-    struct cls_conjunction *conjunctions;
-    size_t n, allocated;
-};
-
-uint32_t expr_to_matches(const struct expr *,
-                         bool (*lookup_port)(const void *aux,
-                                             const char *port_name,
-                                             unsigned int *portp),
-                         const void *aux,
-                         struct hmap *matches);
-void expr_matches_destroy(struct hmap *matches);
-void expr_matches_print(const struct hmap *matches, FILE *);
-
-/* Action parsing helper. */
-
-char *expr_parse_assignment(struct lexer *lexer, struct expr_field *dst,
-                            const struct shash *symtab,
-                            bool (*lookup_port)(const void *aux,
-                                                const char *port_name,
-                                                unsigned int *portp),
-                            const void *aux,
-                            struct ofpbuf *ofpacts, struct expr **prereqsp)
-    OVS_WARN_UNUSED_RESULT;
-char *expr_parse_exchange(struct lexer *lexer, struct expr_field *dst,
-                          const struct shash *symtab,
-                          bool (*lookup_port)(const void *aux,
-                                              const char *port_name,
-                                              unsigned int *portp),
-                          const void *aux,
-                          struct ofpbuf *ofpacts, struct expr **prereqsp)
-    OVS_WARN_UNUSED_RESULT;
-char *expr_parse_field(struct lexer *lexer, const struct shash *symtab,
-                       struct expr_field *field)
-    OVS_WARN_UNUSED_RESULT;
-char *expr_expand_field(struct lexer *lexer, const struct shash *symtab,
-                        const struct expr_field *orig_field,
-                        int n_bits, bool rw,
-                        struct mf_subfield *sf, struct expr **prereqsp)
-    OVS_WARN_UNUSED_RESULT;
-
-/* Type of a "union expr_constant" or "struct expr_constant_set". */
-enum expr_constant_type {
-    EXPR_C_INTEGER,
-    EXPR_C_STRING
-};
-
-/* A string or integer constant (one must know which from context). */
-union expr_constant {
-    /* Integer constant.
-     *
-     * The width of a constant isn't always clear, e.g. if you write "1",
-     * there's no way to tell whether you mean for that to be a 1-bit constant
-     * or a 128-bit constant or somewhere in between. */
-    struct {
-        union mf_subvalue value;
-        union mf_subvalue mask; /* Only initialized if 'masked'. */
-        bool masked;
-
-        enum lex_format format; /* From the constant's lex_token. */
-    };
-
-    /* Null-terminated string constant. */
-    char *string;
-};
-
-/* A collection of "union expr_constant"s of the same type. */
-struct expr_constant_set {
-    union expr_constant *values;  /* Constants. */
-    size_t n_values;              /* Number of constants. */
-    enum expr_constant_type type; /* Type of the constants. */
-    bool in_curlies;              /* Whether the constants were in {}. */
-};
-
-char *expr_parse_constant_set(struct lexer *, const struct shash *symtab,
-                              struct expr_constant_set *cs)
-    OVS_WARN_UNUSED_RESULT;
-void expr_constant_set_destroy(struct expr_constant_set *cs);
-
-
-/* Address sets, aka "macros".
- *
- * Instead of referring to a set of value as:
- *    {addr1, addr2, ..., addrN}
- * You can register a set of values and refer to them as:
- *    $name
- * The macros should all have integer/masked-integer values.
- * The values that don't qualify are ignored.
- */
-
-void expr_macros_add(struct shash *macros, const char *name,
-                     const char * const *values, size_t n_values);
-void expr_macros_remove(struct shash *macros, const char *name);
-void expr_macros_destroy(struct shash *macros);
-
-#endif /* ovn/expr.h */
diff --git a/ovn/lib/lex.c b/ovn/lib/lex.c
index 79aa221..95edeaf 100644
--- a/ovn/lib/lex.c
+++ b/ovn/lib/lex.c
@@ -15,12 +15,12 @@
  */
 
 #include <config.h>
-#include "lex.h"
 #include <ctype.h>
 #include <errno.h>
 #include <stdarg.h>
 #include "openvswitch/dynamic-string.h"
 #include "openvswitch/json.h"
+#include "ovn/lex.h"
 #include "packets.h"
 #include "util.h"
 
diff --git a/ovn/lib/lex.h b/ovn/lib/lex.h
deleted file mode 100644
index 4de48c7..0000000
--- a/ovn/lib/lex.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2015, 2016 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef OVN_LEX_H
-#define OVN_LEX_H 1
-
-/* OVN lexical analyzer
- * ====================
- *
- * This is a simple lexical analyzer (or tokenizer) for OVN match expressions
- * and ACLs. */
-
-#include "openvswitch/meta-flow.h"
-
-struct ds;
-
-/* Token type. */
-enum lex_type {
-    LEX_T_END,                  /* end of input */
-
-    /* Tokens with auxiliary data. */
-    LEX_T_ID,                   /* foo */
-    LEX_T_STRING,               /* "foo" */
-    LEX_T_INTEGER,              /* 12345 or 1.2.3.4 or ::1 or 01:02:03:04:05 */
-    LEX_T_MASKED_INTEGER,       /* 12345/10 or 1.2.0.0/16 or ::2/127 or... */
-    LEX_T_MACRO,                /* $NAME */
-    LEX_T_ERROR,                /* invalid input */
-
-    /* Bare tokens. */
-    LEX_T_LPAREN,               /* ( */
-    LEX_T_RPAREN,               /* ) */
-    LEX_T_LCURLY,               /* { */
-    LEX_T_RCURLY,               /* } */
-    LEX_T_LSQUARE,              /* [ */
-    LEX_T_RSQUARE,              /* ] */
-    LEX_T_EQ,                   /* == */
-    LEX_T_NE,                   /* != */
-    LEX_T_LT,                   /* < */
-    LEX_T_LE,                   /* <= */
-    LEX_T_GT,                   /* > */
-    LEX_T_GE,                   /* >= */
-    LEX_T_LOG_NOT,              /* ! */
-    LEX_T_LOG_AND,              /* && */
-    LEX_T_LOG_OR,               /* || */
-    LEX_T_ELLIPSIS,             /* .. */
-    LEX_T_COMMA,                /* , */
-    LEX_T_SEMICOLON,            /* ; */
-    LEX_T_EQUALS,               /* = */
-    LEX_T_EXCHANGE,             /* <-> */
-    LEX_T_DECREMENT,            /* -- */
-    LEX_T_COLON,                /* : */
-};
-
-/* Subtype for LEX_T_INTEGER and LEX_T_MASKED_INTEGER tokens.
- *
- * These do not change the semantics of a token; instead, they determine the
- * format used when a token is serialized back to a text form.  That's
- * important because 3232268289 is meaningless to a human whereas 192.168.128.1
- * has some actual significance. */
-enum lex_format {
-    LEX_F_DECIMAL,
-    LEX_F_HEXADECIMAL,
-    LEX_F_IPV4,
-    LEX_F_IPV6,
-    LEX_F_ETHERNET,
-};
-const char *lex_format_to_string(enum lex_format);
-
-/* A token. */
-struct lex_token {
-    /* One of LEX_*. */
-    enum lex_type type;
-
-    /* Meaningful for LEX_T_ID, LEX_T_STRING, LEX_T_ERROR, LEX_T_MACRO only.
-     * For these token types, 's' may point to 'buffer'; otherwise, it points
-     * to malloc()ed memory owned by the token.
-     *
-     * Must be NULL for other token types.
-     *
-     * For LEX_T_MACRO, 's' does not include the leading $. */
-    char *s;
-
-    /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER only. */
-    enum lex_format format;
-
-    union {
-        /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER only. */
-        struct {
-            union mf_subvalue value; /* LEX_T_INTEGER, LEX_T_MASKED_INTEGER. */
-            union mf_subvalue mask;  /* LEX_T_MASKED_INTEGER only. */
-        };
-
-        /* LEX_T_ID, LEX_T_STRING, LEX_T_ERROR, LEX_T_MACRO only. */
-        char buffer[256];
-    };
-};
-
-void lex_token_init(struct lex_token *);
-void lex_token_destroy(struct lex_token *);
-void lex_token_swap(struct lex_token *, struct lex_token *);
-void lex_token_strcpy(struct lex_token *, const char *s, size_t length);
-void lex_token_strset(struct lex_token *, char *s);
-void lex_token_vsprintf(struct lex_token *, const char *format, va_list args);
-
-void lex_token_format(const struct lex_token *, struct ds *);
-const char *lex_token_parse(struct lex_token *, const char *input,
-                            const char **startp);
-
-/* A lexical analyzer. */
-struct lexer {
-    const char *input;          /* Remaining input (not owned by lexer). */
-    const char *start;          /* Start of current token in 'input'. */
-    struct lex_token token;     /* Current token (owned by lexer). */
-};
-
-void lexer_init(struct lexer *, const char *input);
-void lexer_destroy(struct lexer *);
-
-enum lex_type lexer_get(struct lexer *);
-enum lex_type lexer_lookahead(const struct lexer *);
-bool lexer_match(struct lexer *, enum lex_type);
-bool lexer_match_id(struct lexer *, const char *id);
-bool lexer_is_int(const struct lexer *);
-bool lexer_get_int(struct lexer *, int *value);
-
-#endif /* ovn/lex.h */
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index a3d1672..b563586 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -26,7 +26,7 @@
 #include "hash.h"
 #include "openvswitch/hmap.h"
 #include "openvswitch/json.h"
-#include "ovn/lib/lex.h"
+#include "ovn/lex.h"
 #include "ovn/lib/ovn-nb-idl.h"
 #include "ovn/lib/ovn-sb-idl.h"
 #include "ovn/lib/ovn-util.h"
diff --git a/tests/test-ovn.c b/tests/test-ovn.c
index 26055bb..ffb4e50 100644
--- a/tests/test-ovn.c
+++ b/tests/test-ovn.c
@@ -26,9 +26,9 @@
 #include "openvswitch/ofp-actions.h"
 #include "openvswitch/ofpbuf.h"
 #include "openvswitch/vlog.h"
-#include "ovn/lib/actions.h"
-#include "ovn/lib/expr.h"
-#include "ovn/lib/lex.h"
+#include "ovn/actions.h"
+#include "ovn/expr.h"
+#include "ovn/lex.h"
 #include "ovn/lib/ovn-dhcp.h"
 #include "ovs-thread.h"
 #include "ovstest.h"
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to