summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorBen Pfaff <blp@ovn.org>2016-08-15 11:34:02 -0700
committerBen Pfaff <blp@ovn.org>2016-08-15 11:36:29 -0700
commitd5a76da4c227a0b8084d75b982f5e5ac4eefd06f (patch)
tree5c2a3628819f88714f06fd1663e2bc706292f19d /include
parent61591ad987635b3f6ae1af284073edcfcb7eff17 (diff)
downloadopenvswitch-d5a76da4c227a0b8084d75b982f5e5ac4eefd06f.tar.gz
ovn: Rewrite logical action parsing and encoding library.
Until now, parsing logical actions and encoding them into OpenFlow has happened in a single step. An upcoming commit will want to examine actions after parsing without encoding them into OpenFlow. This commit refactors OVN logical actions to make this possible. The new form of the OVN action handling is closely modeled on ofp-actions in the OVS core library. Notable differences are that OVN actions are always fixed-length and that individual OVN actions can have destructors (and thus can contain pointers to data that need to be freed when the actions are destroyed). Signed-off-by: Ben Pfaff <blp@ovn.org> Acked-by: Ryan Moats <rmoats@us.ibm.com> Acked-by: Justin Pettit <jpettit@ovn.org>
Diffstat (limited to 'include')
-rw-r--r--include/ovn/actions.h295
-rw-r--r--include/ovn/expr.h41
2 files changed, 299 insertions, 37 deletions
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index f1f38c6ab..2c0afd4b5 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -20,17 +20,263 @@
#include <stdbool.h>
#include <stdint.h>
#include "compiler.h"
-#include "openvswitch/hmap.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_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(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)
+
+/* 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;
+};
+
+/* OVNACT_NEXT, OVNACT_CT_NEXT. */
+struct ovnact_next {
+ struct ovnact ovnact;
+ uint8_t ltable; /* Logical table ID of next 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_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. */
+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;
+};
+
+/* 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 {
@@ -108,17 +354,45 @@ struct action_header {
};
BUILD_ASSERT_DECL(sizeof(struct action_header) == 8);
-struct action_params {
+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 */
+ /* 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;
+ /* 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_tables) 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. */
+ uint8_t n_tables; /* Number of flow tables. */
+ uint8_t cur_ltable; /* 0 <= cur_ltable < n_tables. */
+};
+
+char *ovnacts_parse(struct lexer *, const struct ovnact_parse_params *,
+ struct ofpbuf *ovnacts, struct expr **prereqsp)
+ OVS_WARN_UNUSED_RESULT;
+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,
@@ -151,19 +425,16 @@ struct action_params {
*
* - '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 mac_bind_ptable; /* OpenFlow table for 'get_arp'/'get_nd' 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;
+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 */
diff --git a/include/ovn/expr.h b/include/ovn/expr.h
index df22895c7..50cb73fa0 100644
--- a/include/ovn/expr.h
+++ b/include/ovn/expr.h
@@ -60,6 +60,7 @@
#include "openvswitch/meta-flow.h"
struct ds;
+struct expr;
struct ofpbuf;
struct shash;
struct simap;
@@ -264,6 +265,9 @@ struct expr_field {
int n_bits; /* Number of bits. */
};
+char *expr_field_parse(struct lexer *lexer, const struct shash *symtab,
+ struct expr_field *field, struct expr **prereqsp)
+ OVS_WARN_UNUSED_RESULT;
void expr_field_format(const struct expr_field *, struct ds *);
struct expr_symbol *expr_symtab_add_field(struct shash *symtab,
@@ -401,30 +405,9 @@ 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)
+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 {
@@ -451,6 +434,14 @@ union expr_constant {
char *string;
};
+char *expr_constant_parse(struct lexer *, const struct expr_field *,
+ union expr_constant *)
+ OVS_WARN_UNUSED_RESULT;
+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. */
@@ -459,9 +450,9 @@ struct expr_constant_set {
bool in_curlies; /* Whether the constants were in {}. */
};
-char *expr_parse_constant_set(struct lexer *, const struct shash *symtab,
- struct expr_constant_set *cs)
+char *expr_constant_set_parse(struct lexer *, struct expr_constant_set *cs)
OVS_WARN_UNUSED_RESULT;
+void expr_constant_set_format(const struct expr_constant_set *, struct ds *);
void expr_constant_set_destroy(struct expr_constant_set *cs);