summaryrefslogtreecommitdiff
path: root/include/ovn/actions.h
blob: d2510fd3c4a7b2c170094187ed7aad5298219a6e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
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 */