openflow build environment setup
This commit is contained in:
489
openflow/include/ovn/actions.h
Normal file
489
openflow/include/ovn/actions.h
Normal file
@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 2017 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 "expr.h"
|
||||
#include "openvswitch/dynamic-string.h"
|
||||
#include "openvswitch/hmap.h"
|
||||
#include "openvswitch/uuid.h"
|
||||
#include "util.h"
|
||||
|
||||
struct expr;
|
||||
struct lexer;
|
||||
struct ofpbuf;
|
||||
struct shash;
|
||||
struct simap;
|
||||
|
||||
/* List of OVN logical actions.
|
||||
*
|
||||
* This macro is used directly only internally by this header and its
|
||||
* corresponding .c file, but the list is still of interest to developers.
|
||||
*
|
||||
* Each OVNACT invocation has the following parameters:
|
||||
*
|
||||
* 1. <ENUM>, used below in the enum definition of OVNACT_<ENUM>, and
|
||||
* elsewhere.
|
||||
*
|
||||
* 2. <STRUCT> corresponding to a structure "struct <STRUCT>", that must be a
|
||||
* defined below. This structure must be an abstract definition of the
|
||||
* action. Its first member must have type "struct ovnact" and name
|
||||
* "ovnact". The structure must have a fixed length, that is, it may not
|
||||
* end with a flexible array member.
|
||||
*/
|
||||
#define OVNACTS \
|
||||
OVNACT(OUTPUT, ovnact_null) \
|
||||
OVNACT(NEXT, ovnact_next) \
|
||||
OVNACT(LOAD, ovnact_load) \
|
||||
OVNACT(MOVE, ovnact_move) \
|
||||
OVNACT(EXCHANGE, ovnact_move) \
|
||||
OVNACT(DEC_TTL, ovnact_null) \
|
||||
OVNACT(CT_NEXT, ovnact_ct_next) \
|
||||
OVNACT(CT_COMMIT, ovnact_ct_commit) \
|
||||
OVNACT(CT_DNAT, ovnact_ct_nat) \
|
||||
OVNACT(CT_SNAT, ovnact_ct_nat) \
|
||||
OVNACT(CT_LB, ovnact_ct_lb) \
|
||||
OVNACT(CT_CLEAR, ovnact_null) \
|
||||
OVNACT(CLONE, ovnact_nest) \
|
||||
OVNACT(ARP, ovnact_nest) \
|
||||
OVNACT(ND_NA, ovnact_nest) \
|
||||
OVNACT(GET_ARP, ovnact_get_mac_bind) \
|
||||
OVNACT(PUT_ARP, ovnact_put_mac_bind) \
|
||||
OVNACT(GET_ND, ovnact_get_mac_bind) \
|
||||
OVNACT(PUT_ND, ovnact_put_mac_bind) \
|
||||
OVNACT(PUT_DHCPV4_OPTS, ovnact_put_dhcp_opts) \
|
||||
OVNACT(PUT_DHCPV6_OPTS, ovnact_put_dhcp_opts) \
|
||||
OVNACT(SET_QUEUE, ovnact_set_queue)
|
||||
|
||||
/* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
|
||||
enum OVS_PACKED_ENUM ovnact_type {
|
||||
#define OVNACT(ENUM, STRUCT) OVNACT_##ENUM,
|
||||
OVNACTS
|
||||
#undef OVNACT
|
||||
};
|
||||
|
||||
/* Define N_OVNACTS to the number of types of ovnacts. */
|
||||
enum {
|
||||
#define OVNACT(ENUM, STRUCT) + 1
|
||||
N_OVNACTS = OVNACTS
|
||||
#undef OVNACT
|
||||
};
|
||||
|
||||
/* Header for an action.
|
||||
*
|
||||
* Each action is a structure "struct ovnact_*" that begins with "struct
|
||||
* ovnact", usually followed by other data that describes the action. Actions
|
||||
* are padded out to a multiple of OVNACT_ALIGNTO bytes in length.
|
||||
*/
|
||||
struct ovnact {
|
||||
/* We want the space advantage of an 8-bit type here on every
|
||||
* implementation, without giving up the advantage of having a useful type
|
||||
* on implementations that support packed enums. */
|
||||
#ifdef HAVE_PACKED_ENUM
|
||||
enum ovnact_type type; /* OVNACT_*. */
|
||||
#else
|
||||
uint8_t type; /* OVNACT_* */
|
||||
#endif
|
||||
uint8_t pad; /* Pad to multiple of 16 bits. */
|
||||
|
||||
uint16_t len; /* Length of the action, in bytes, including
|
||||
* struct ovnact, excluding padding. */
|
||||
};
|
||||
BUILD_ASSERT_DECL(sizeof(struct ovnact) == 4);
|
||||
|
||||
/* Alignment. */
|
||||
#define OVNACT_ALIGNTO 8
|
||||
#define OVNACT_ALIGN(SIZE) ROUND_UP(SIZE, OVNACT_ALIGNTO)
|
||||
|
||||
/* Returns the ovnact following 'ovnact'. */
|
||||
static inline struct ovnact *
|
||||
ovnact_next(const struct ovnact *ovnact)
|
||||
{
|
||||
return (void *) ((uint8_t *) ovnact + OVNACT_ALIGN(ovnact->len));
|
||||
}
|
||||
|
||||
struct ovnact *ovnact_next_flattened(const struct ovnact *);
|
||||
|
||||
static inline struct ovnact *
|
||||
ovnact_end(const struct ovnact *ovnacts, size_t ovnacts_len)
|
||||
{
|
||||
return (void *) ((uint8_t *) ovnacts + ovnacts_len);
|
||||
}
|
||||
|
||||
/* Assigns POS to each ovnact, in turn, in the OVNACTS_LEN bytes of ovnacts
|
||||
* starting at OVNACTS. */
|
||||
#define OVNACT_FOR_EACH(POS, OVNACTS, OVNACTS_LEN) \
|
||||
for ((POS) = (OVNACTS); (POS) < ovnact_end(OVNACTS, OVNACTS_LEN); \
|
||||
(POS) = ovnact_next(POS))
|
||||
|
||||
/* Action structure for each OVNACT_*. */
|
||||
|
||||
/* Action structure for actions that do not have any extra data beyond the
|
||||
* action type. */
|
||||
struct ovnact_null {
|
||||
struct ovnact ovnact;
|
||||
};
|
||||
|
||||
/* Logical pipeline in which a set of actions is executed. */
|
||||
enum ovnact_pipeline {
|
||||
OVNACT_P_INGRESS,
|
||||
OVNACT_P_EGRESS,
|
||||
};
|
||||
|
||||
/* OVNACT_NEXT. */
|
||||
struct ovnact_next {
|
||||
struct ovnact ovnact;
|
||||
|
||||
/* Arguments. */
|
||||
uint8_t ltable; /* Logical table ID of next table. */
|
||||
enum ovnact_pipeline pipeline; /* Pipeline of next table. */
|
||||
|
||||
/* Information about the flow that the action is in. This does not affect
|
||||
* behavior, since the implementation of "next" doesn't depend on the
|
||||
* source table or pipeline. It does affect how ovnacts_format() prints
|
||||
* the action. */
|
||||
uint8_t src_ltable; /* Logical table ID of source table. */
|
||||
enum ovnact_pipeline src_pipeline; /* Pipeline of source table. */
|
||||
};
|
||||
|
||||
/* OVNACT_LOAD. */
|
||||
struct ovnact_load {
|
||||
struct ovnact ovnact;
|
||||
struct expr_field dst;
|
||||
union expr_constant imm;
|
||||
};
|
||||
|
||||
/* OVNACT_MOVE, OVNACT_EXCHANGE. */
|
||||
struct ovnact_move {
|
||||
struct ovnact ovnact;
|
||||
struct expr_field lhs;
|
||||
struct expr_field rhs;
|
||||
};
|
||||
|
||||
/* OVNACT_CT_NEXT. */
|
||||
struct ovnact_ct_next {
|
||||
struct ovnact ovnact;
|
||||
uint8_t ltable; /* Logical table ID of next table. */
|
||||
};
|
||||
|
||||
/* OVNACT_CT_COMMIT. */
|
||||
struct ovnact_ct_commit {
|
||||
struct ovnact ovnact;
|
||||
uint32_t ct_mark, ct_mark_mask;
|
||||
ovs_be128 ct_label, ct_label_mask;
|
||||
};
|
||||
|
||||
/* OVNACT_CT_DNAT, OVNACT_CT_SNAT. */
|
||||
struct ovnact_ct_nat {
|
||||
struct ovnact ovnact;
|
||||
ovs_be32 ip;
|
||||
uint8_t ltable; /* Logical table ID of next table. */
|
||||
};
|
||||
|
||||
struct ovnact_ct_lb_dst {
|
||||
ovs_be32 ip;
|
||||
uint16_t port;
|
||||
};
|
||||
|
||||
/* OVNACT_CT_LB. */
|
||||
struct ovnact_ct_lb {
|
||||
struct ovnact ovnact;
|
||||
struct ovnact_ct_lb_dst *dsts;
|
||||
size_t n_dsts;
|
||||
uint8_t ltable; /* Logical table ID of next table. */
|
||||
};
|
||||
|
||||
/* OVNACT_ARP, OVNACT_ND_NA, OVNACT_CLONE. */
|
||||
struct ovnact_nest {
|
||||
struct ovnact ovnact;
|
||||
struct ovnact *nested;
|
||||
size_t nested_len;
|
||||
};
|
||||
|
||||
/* OVNACT_GET_ARP, OVNACT_GET_ND. */
|
||||
struct ovnact_get_mac_bind {
|
||||
struct ovnact ovnact;
|
||||
struct expr_field port; /* Logical port name. */
|
||||
struct expr_field ip; /* 32-bit or 128-bit IP address. */
|
||||
};
|
||||
|
||||
/* OVNACT_PUT_ARP, ONVACT_PUT_ND. */
|
||||
struct ovnact_put_mac_bind {
|
||||
struct ovnact ovnact;
|
||||
struct expr_field port; /* Logical port name. */
|
||||
struct expr_field ip; /* 32-bit or 128-bit IP address. */
|
||||
struct expr_field mac; /* 48-bit Ethernet address. */
|
||||
};
|
||||
|
||||
struct ovnact_dhcp_option {
|
||||
const struct dhcp_opts_map *option;
|
||||
struct expr_constant_set value;
|
||||
};
|
||||
|
||||
/* OVNACT_PUT_DHCPV4_OPTS, OVNACT_PUT_DHCPV6_OPTS. */
|
||||
struct ovnact_put_dhcp_opts {
|
||||
struct ovnact ovnact;
|
||||
struct expr_field dst; /* 1-bit destination field. */
|
||||
struct ovnact_dhcp_option *options;
|
||||
size_t n_options;
|
||||
};
|
||||
|
||||
/* Valid arguments to SET_QUEUE action.
|
||||
*
|
||||
* QDISC_MIN_QUEUE_ID is the default queue, so user-defined queues should
|
||||
* start at QDISC_MIN_QUEUE_ID+1. */
|
||||
#define QDISC_MIN_QUEUE_ID 0
|
||||
#define QDISC_MAX_QUEUE_ID 0xf000
|
||||
|
||||
/* OVNACT_SET_QUEUE. */
|
||||
struct ovnact_set_queue {
|
||||
struct ovnact ovnact;
|
||||
uint16_t queue_id;
|
||||
};
|
||||
|
||||
/* Internal use by the helpers below. */
|
||||
void ovnact_init(struct ovnact *, enum ovnact_type, size_t len);
|
||||
void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len);
|
||||
|
||||
/* For each OVNACT_<ENUM> with a corresponding struct <STRUCT>, this defines
|
||||
* the following commonly useful functions:
|
||||
*
|
||||
* struct <STRUCT> *ovnact_put_<ENUM>(struct ofpbuf *ovnacts);
|
||||
*
|
||||
* Appends a new 'ovnact', of length OVNACT_<ENUM>_SIZE, to 'ovnacts',
|
||||
* initializes it with ovnact_init_<ENUM>(), and returns it. Also sets
|
||||
* 'ovnacts->header' to the returned action.
|
||||
*
|
||||
* struct <STRUCT> *ovnact_get_<ENUM>(const struct ovnact *ovnact);
|
||||
*
|
||||
* Returns 'ovnact' cast to "struct <STRUCT> *". 'ovnact->type' must be
|
||||
* OVNACT_<ENUM>.
|
||||
*
|
||||
* as well as the following more rarely useful definitions:
|
||||
*
|
||||
* void ovnact_init_<ENUM>(struct <STRUCT> *ovnact);
|
||||
*
|
||||
* Initializes the parts of 'ovnact' that identify it as having type
|
||||
* OVNACT_<ENUM> and length OVNACT_<ENUM>_SIZE and zeros the rest.
|
||||
*
|
||||
* <ENUM>_SIZE
|
||||
*
|
||||
* The size of the action structure, that is, sizeof(struct <STRUCT>)
|
||||
* rounded up to a multiple of OVNACT_ALIGNTO.
|
||||
*/
|
||||
#define OVNACT(ENUM, STRUCT) \
|
||||
BUILD_ASSERT_DECL(offsetof(struct STRUCT, ovnact) == 0); \
|
||||
\
|
||||
enum { OVNACT_##ENUM##_SIZE = OVNACT_ALIGN(sizeof(struct STRUCT)) }; \
|
||||
\
|
||||
static inline struct STRUCT * \
|
||||
ovnact_get_##ENUM(const struct ovnact *ovnact) \
|
||||
{ \
|
||||
ovs_assert(ovnact->type == OVNACT_##ENUM); \
|
||||
return ALIGNED_CAST(struct STRUCT *, ovnact); \
|
||||
} \
|
||||
\
|
||||
static inline struct STRUCT * \
|
||||
ovnact_put_##ENUM(struct ofpbuf *ovnacts) \
|
||||
{ \
|
||||
return ovnact_put(ovnacts, OVNACT_##ENUM, \
|
||||
OVNACT_##ENUM##_SIZE); \
|
||||
} \
|
||||
\
|
||||
static inline void \
|
||||
ovnact_init_##ENUM(struct STRUCT *ovnact) \
|
||||
{ \
|
||||
ovnact_init(&ovnact->ovnact, OVNACT_##ENUM, \
|
||||
OVNACT_##ENUM##_SIZE); \
|
||||
}
|
||||
OVNACTS
|
||||
#undef OVNACT
|
||||
|
||||
#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;
|
||||
bool new_group_id; /* 'True' if 'group_id' was reserved from
|
||||
* group_table's 'group_ids' bitmap. */
|
||||
};
|
||||
|
||||
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,
|
||||
|
||||
/* "nd_na { ...actions... }".
|
||||
*
|
||||
* The actions, in OpenFlow 1.3 format, follow the action_header.
|
||||
*/
|
||||
ACTION_OPCODE_ND_NA,
|
||||
|
||||
/* "put_nd(port, ip6, mac)"
|
||||
*
|
||||
* Arguments are passed through the packet metadata and data, as follows:
|
||||
*
|
||||
* MFF_XXREG0 = ip6
|
||||
* MFF_LOG_INPORT = port
|
||||
* MFF_ETH_SRC = mac
|
||||
*/
|
||||
ACTION_OPCODE_PUT_ND,
|
||||
|
||||
/* "result = put_dhcpv6_opts(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.
|
||||
* - Any number of DHCPv6 options.
|
||||
*/
|
||||
ACTION_OPCODE_PUT_DHCPV6_OPTS,
|
||||
};
|
||||
|
||||
/* Header. */
|
||||
struct action_header {
|
||||
ovs_be32 opcode; /* One of ACTION_OPCODE_* */
|
||||
uint8_t pad[4];
|
||||
};
|
||||
BUILD_ASSERT_DECL(sizeof(struct action_header) == 8);
|
||||
|
||||
struct ovnact_parse_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;
|
||||
|
||||
/* hmap of 'struct dhcp_opts_map' to support 'put_dhcpv6_opts' action */
|
||||
const struct hmap *dhcpv6_opts;
|
||||
|
||||
/* Each OVN flow exists in a logical table within a logical pipeline.
|
||||
* These parameters express this context for a set of OVN actions being
|
||||
* parsed:
|
||||
*
|
||||
* - 'n_tables' is the number of tables in the logical ingress and
|
||||
* egress pipelines, that is, "next" may specify a table less than
|
||||
* or equal to 'n_tables'. If 'n_tables' is 0 then "next" is
|
||||
* disallowed entirely.
|
||||
*
|
||||
* - 'cur_ltable' is the logical table of the current flow, within
|
||||
* 'pipeline'. If cur_ltable + 1 < n_tables, then this defines the
|
||||
* default table that "next" will jump to.
|
||||
*
|
||||
* - 'pipeline' is the logical pipeline. It is the default pipeline to
|
||||
* which 'next' will jump. If 'pipeline' is OVNACT_P_EGRESS, then
|
||||
* 'next' will also be able to jump into the ingress pipeline, but
|
||||
* the reverse is not true. */
|
||||
enum ovnact_pipeline pipeline; /* Logical pipeline. */
|
||||
uint8_t n_tables; /* Number of logical flow tables. */
|
||||
uint8_t cur_ltable; /* 0 <= cur_ltable < n_tables. */
|
||||
};
|
||||
|
||||
bool ovnacts_parse(struct lexer *, const struct ovnact_parse_params *,
|
||||
struct ofpbuf *ovnacts, struct expr **prereqsp);
|
||||
char *ovnacts_parse_string(const char *s, const struct ovnact_parse_params *,
|
||||
struct ofpbuf *ovnacts, struct expr **prereqsp)
|
||||
OVS_WARN_UNUSED_RESULT;
|
||||
|
||||
void ovnacts_format(const struct ovnact[], size_t ovnacts_len, struct ds *);
|
||||
|
||||
struct ovnact_encode_params {
|
||||
/* 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;
|
||||
|
||||
/* 'true' if the flow is for a switch. */
|
||||
bool is_switch;
|
||||
|
||||
/* 'true' if the flow is for a gateway router. */
|
||||
bool is_gateway_router;
|
||||
|
||||
/* 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:
|
||||
*
|
||||
* - 'pipeline' is the logical pipeline in which the actions are
|
||||
* executing.
|
||||
*
|
||||
* - 'ingress_ptable' is the OpenFlow table that corresponds to OVN
|
||||
* ingress table 0.
|
||||
*
|
||||
* - 'egress_ptable' is the OpenFlow table that corresponds to OVN
|
||||
* egress table 0.
|
||||
*
|
||||
* - 'output_ptable' should be the OpenFlow table to which the logical
|
||||
* "output" action will resubmit.
|
||||
*
|
||||
* - 'mac_bind_ptable' should be the OpenFlow table used to track MAC
|
||||
* bindings. */
|
||||
enum ovnact_pipeline pipeline; /* Logical pipeline. */
|
||||
uint8_t ingress_ptable; /* First OpenFlow ingress table. */
|
||||
uint8_t egress_ptable; /* First OpenFlow egress table. */
|
||||
uint8_t output_ptable; /* OpenFlow table for 'output' to resubmit. */
|
||||
uint8_t mac_bind_ptable; /* OpenFlow table for 'get_arp'/'get_nd' to
|
||||
resubmit. */
|
||||
};
|
||||
|
||||
void ovnacts_encode(const struct ovnact[], size_t ovnacts_len,
|
||||
const struct ovnact_encode_params *,
|
||||
struct ofpbuf *ofpacts);
|
||||
|
||||
void ovnacts_free(struct ovnact[], size_t ovnacts_len);
|
||||
|
||||
#endif /* ovn/actions.h */
|
||||
504
openflow/include/ovn/expr.h
Normal file
504
openflow/include/ovn/expr.h
Normal file
@ -0,0 +1,504 @@
|
||||
/*
|
||||
* 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 expr;
|
||||
struct flow;
|
||||
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. 'field' specifies the field.
|
||||
*
|
||||
* 'parent' and 'predicate' are NULL, and 'parent_ofs' is 0.
|
||||
*
|
||||
* Integer fields can be nominal or ordinal (see below). String fields are
|
||||
* always nominal.
|
||||
*
|
||||
* Subfields:
|
||||
*
|
||||
* 'parent' specifies the field (which may itself be a subfield,
|
||||
* recursively) in which the subfield is embedded, and 'parent_ofs' a
|
||||
* bitwise offset from the least-significant bit of the parent. The
|
||||
* subfield can contain a subset of the bits of the parent or all of them
|
||||
* (in the latter case the subfield is really just a synonym for the
|
||||
* parent).
|
||||
*
|
||||
* 'field' and 'predicate' are 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. 'predicate' specifies the Boolean
|
||||
* expression, e.g. "ip4" might expand to "eth.type == 0x800". The
|
||||
* epxression might refer to other predicates, e.g. "icmp4" might expand to
|
||||
* "ip4 && ip4.proto == 1".
|
||||
*
|
||||
* 'field' and 'parent' are NULL, and 'parent_ofs' is 0.
|
||||
*
|
||||
* A predicate that 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; /* Fields only, otherwise NULL. */
|
||||
const struct expr_symbol *parent; /* Subfields only, otherwise NULL. */
|
||||
int parent_ofs; /* Subfields only, otherwise 0. */
|
||||
char *predicate; /* Predicates only, otherwise NULL. */
|
||||
|
||||
enum expr_level level;
|
||||
|
||||
char *prereqs;
|
||||
bool must_crossproduct;
|
||||
bool rw;
|
||||
};
|
||||
|
||||
void expr_symbol_format(const struct expr_symbol *, struct ds *);
|
||||
|
||||
/* 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. */
|
||||
};
|
||||
|
||||
bool expr_field_parse(struct lexer *, const struct shash *symtab,
|
||||
struct expr_field *, struct expr **prereqsp);
|
||||
void expr_field_format(const struct expr_field *, struct ds *);
|
||||
|
||||
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. */
|
||||
EXPR_T_CONDITION, /* Conditional to be evaluated in the
|
||||
* controller during expr_simplify(),
|
||||
* prior to constructing OpenFlow matches. */
|
||||
};
|
||||
|
||||
/* Expression condition type. */
|
||||
enum expr_cond_type {
|
||||
EXPR_COND_CHASSIS_RESIDENT, /* Check if specified logical port name is
|
||||
* resident on the controller chassis. */
|
||||
};
|
||||
|
||||
/* 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;
|
||||
|
||||
/* EXPR_T_CONDITION. */
|
||||
struct {
|
||||
enum expr_cond_type type;
|
||||
bool not;
|
||||
/* XXX Should arguments for conditions be generic? */
|
||||
char *string;
|
||||
} cond;
|
||||
};
|
||||
};
|
||||
|
||||
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 *addr_sets);
|
||||
struct expr *expr_parse_string(const char *, const struct shash *symtab,
|
||||
const struct shash *addr_sets,
|
||||
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 *,
|
||||
bool (*is_chassis_resident)(const void *c_aux,
|
||||
const char *port_name),
|
||||
const void *c_aux);
|
||||
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 *);
|
||||
|
||||
char *expr_parse_microflow(const char *, const struct shash *symtab,
|
||||
const struct shash *addr_sets,
|
||||
bool (*lookup_port)(const void *aux,
|
||||
const char *port_name,
|
||||
unsigned int *portp),
|
||||
const void *aux, struct flow *uflow)
|
||||
OVS_WARN_UNUSED_RESULT;
|
||||
|
||||
bool expr_evaluate(const struct expr *, const struct flow *uflow,
|
||||
bool (*lookup_port)(const void *aux, const char *port_name,
|
||||
unsigned int *portp),
|
||||
const void *aux);
|
||||
|
||||
/* 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_type_check(const struct expr_field *, int n_bits, bool rw)
|
||||
OVS_WARN_UNUSED_RESULT;
|
||||
struct mf_subfield expr_resolve_field(const struct expr_field *);
|
||||
|
||||
/* 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;
|
||||
};
|
||||
|
||||
bool expr_constant_parse(struct lexer *, const struct expr_field *,
|
||||
union expr_constant *);
|
||||
void expr_constant_format(const union expr_constant *,
|
||||
enum expr_constant_type, struct ds *);
|
||||
void expr_constant_destroy(const union expr_constant *,
|
||||
enum expr_constant_type);
|
||||
|
||||
/* 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 {}. */
|
||||
};
|
||||
|
||||
bool expr_constant_set_parse(struct lexer *, struct expr_constant_set *);
|
||||
void expr_constant_set_format(const struct expr_constant_set *, struct ds *);
|
||||
void expr_constant_set_destroy(struct expr_constant_set *cs);
|
||||
|
||||
|
||||
/* Address sets.
|
||||
*
|
||||
* 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 address set entries should all have integer/masked-integer values.
|
||||
* The values that don't qualify are ignored.
|
||||
*/
|
||||
|
||||
void expr_addr_sets_add(struct shash *addr_sets, const char *name,
|
||||
const char * const *values, size_t n_values);
|
||||
void expr_addr_sets_remove(struct shash *addr_sets, const char *name);
|
||||
void expr_addr_sets_destroy(struct shash *addr_sets);
|
||||
|
||||
#endif /* ovn/expr.h */
|
||||
151
openflow/include/ovn/lex.h
Normal file
151
openflow/include/ovn/lex.h
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, 2017 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). */
|
||||
char *error; /* Error message, if any (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_force_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);
|
||||
bool lexer_force_int(struct lexer *, int *value);
|
||||
|
||||
bool lexer_force_end(struct lexer *);
|
||||
|
||||
void lexer_error(struct lexer *, const char *message, ...)
|
||||
OVS_PRINTF_FORMAT(2, 3);
|
||||
void lexer_syntax_error(struct lexer *, const char *message, ...)
|
||||
OVS_PRINTF_FORMAT(2, 3);
|
||||
|
||||
char *lexer_steal_error(struct lexer *);
|
||||
|
||||
#endif /* ovn/lex.h */
|
||||
Reference in New Issue
Block a user