]>
Commit | Line | Data |
---|---|---|
3b7cb7e1 | 1 | /* |
b3bd2c33 | 2 | * Copyright (c) 2015, 2016, 2017 Nicira, Inc. |
3b7cb7e1 BP |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at: | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | ||
17 | #ifndef OVN_ACTIONS_H | |
18 | #define OVN_ACTIONS_H 1 | |
19 | ||
f1c16a85 | 20 | #include <stdbool.h> |
3b7cb7e1 BP |
21 | #include <stdint.h> |
22 | #include "compiler.h" | |
d5a76da4 | 23 | #include "expr.h" |
467085fd | 24 | #include "openvswitch/dynamic-string.h" |
d5a76da4 | 25 | #include "openvswitch/hmap.h" |
fa44a4a3 | 26 | #include "openvswitch/uuid.h" |
6335d074 | 27 | #include "util.h" |
3b7cb7e1 | 28 | |
a6095f81 | 29 | struct expr; |
3b7cb7e1 BP |
30 | struct lexer; |
31 | struct ofpbuf; | |
32 | struct shash; | |
33 | struct simap; | |
34 | ||
d5a76da4 BP |
35 | /* List of OVN logical actions. |
36 | * | |
37 | * This macro is used directly only internally by this header and its | |
38 | * corresponding .c file, but the list is still of interest to developers. | |
39 | * | |
40 | * Each OVNACT invocation has the following parameters: | |
41 | * | |
42 | * 1. <ENUM>, used below in the enum definition of OVNACT_<ENUM>, and | |
43 | * elsewhere. | |
44 | * | |
45 | * 2. <STRUCT> corresponding to a structure "struct <STRUCT>", that must be a | |
46 | * defined below. This structure must be an abstract definition of the | |
47 | * action. Its first member must have type "struct ovnact" and name | |
48 | * "ovnact". The structure must have a fixed length, that is, it may not | |
49 | * end with a flexible array member. | |
50 | */ | |
51 | #define OVNACTS \ | |
52 | OVNACT(OUTPUT, ovnact_null) \ | |
53 | OVNACT(NEXT, ovnact_next) \ | |
54 | OVNACT(LOAD, ovnact_load) \ | |
55 | OVNACT(MOVE, ovnact_move) \ | |
56 | OVNACT(EXCHANGE, ovnact_move) \ | |
57 | OVNACT(DEC_TTL, ovnact_null) \ | |
ebb467ff | 58 | OVNACT(CT_NEXT, ovnact_ct_next) \ |
d5a76da4 BP |
59 | OVNACT(CT_COMMIT, ovnact_ct_commit) \ |
60 | OVNACT(CT_DNAT, ovnact_ct_nat) \ | |
61 | OVNACT(CT_SNAT, ovnact_ct_nat) \ | |
62 | OVNACT(CT_LB, ovnact_ct_lb) \ | |
db0e819b | 63 | OVNACT(CT_CLEAR, ovnact_null) \ |
b3bd2c33 | 64 | OVNACT(CLONE, ovnact_nest) \ |
d5a76da4 BP |
65 | OVNACT(ARP, ovnact_nest) \ |
66 | OVNACT(ND_NA, ovnact_nest) \ | |
67 | OVNACT(GET_ARP, ovnact_get_mac_bind) \ | |
68 | OVNACT(PUT_ARP, ovnact_put_mac_bind) \ | |
69 | OVNACT(GET_ND, ovnact_get_mac_bind) \ | |
70 | OVNACT(PUT_ND, ovnact_put_mac_bind) \ | |
71 | OVNACT(PUT_DHCPV4_OPTS, ovnact_put_dhcp_opts) \ | |
a6095f81 BS |
72 | OVNACT(PUT_DHCPV6_OPTS, ovnact_put_dhcp_opts) \ |
73 | OVNACT(SET_QUEUE, ovnact_set_queue) | |
d5a76da4 BP |
74 | |
75 | /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */ | |
76 | enum OVS_PACKED_ENUM ovnact_type { | |
77 | #define OVNACT(ENUM, STRUCT) OVNACT_##ENUM, | |
78 | OVNACTS | |
79 | #undef OVNACT | |
80 | }; | |
81 | ||
82 | /* Define N_OVNACTS to the number of types of ovnacts. */ | |
83 | enum { | |
84 | #define OVNACT(ENUM, STRUCT) + 1 | |
85 | N_OVNACTS = OVNACTS | |
86 | #undef OVNACT | |
87 | }; | |
88 | ||
89 | /* Header for an action. | |
90 | * | |
91 | * Each action is a structure "struct ovnact_*" that begins with "struct | |
92 | * ovnact", usually followed by other data that describes the action. Actions | |
93 | * are padded out to a multiple of OVNACT_ALIGNTO bytes in length. | |
94 | */ | |
95 | struct ovnact { | |
96 | /* We want the space advantage of an 8-bit type here on every | |
97 | * implementation, without giving up the advantage of having a useful type | |
98 | * on implementations that support packed enums. */ | |
99 | #ifdef HAVE_PACKED_ENUM | |
100 | enum ovnact_type type; /* OVNACT_*. */ | |
101 | #else | |
102 | uint8_t type; /* OVNACT_* */ | |
103 | #endif | |
104 | uint8_t pad; /* Pad to multiple of 16 bits. */ | |
105 | ||
106 | uint16_t len; /* Length of the action, in bytes, including | |
107 | * struct ovnact, excluding padding. */ | |
108 | }; | |
109 | BUILD_ASSERT_DECL(sizeof(struct ovnact) == 4); | |
110 | ||
111 | /* Alignment. */ | |
112 | #define OVNACT_ALIGNTO 8 | |
113 | #define OVNACT_ALIGN(SIZE) ROUND_UP(SIZE, OVNACT_ALIGNTO) | |
114 | ||
115 | /* Returns the ovnact following 'ovnact'. */ | |
116 | static inline struct ovnact * | |
117 | ovnact_next(const struct ovnact *ovnact) | |
118 | { | |
119 | return (void *) ((uint8_t *) ovnact + OVNACT_ALIGN(ovnact->len)); | |
120 | } | |
121 | ||
122 | struct ovnact *ovnact_next_flattened(const struct ovnact *); | |
123 | ||
124 | static inline struct ovnact * | |
125 | ovnact_end(const struct ovnact *ovnacts, size_t ovnacts_len) | |
126 | { | |
127 | return (void *) ((uint8_t *) ovnacts + ovnacts_len); | |
128 | } | |
129 | ||
130 | /* Assigns POS to each ovnact, in turn, in the OVNACTS_LEN bytes of ovnacts | |
131 | * starting at OVNACTS. */ | |
132 | #define OVNACT_FOR_EACH(POS, OVNACTS, OVNACTS_LEN) \ | |
133 | for ((POS) = (OVNACTS); (POS) < ovnact_end(OVNACTS, OVNACTS_LEN); \ | |
134 | (POS) = ovnact_next(POS)) | |
135 | \f | |
136 | /* Action structure for each OVNACT_*. */ | |
137 | ||
138 | /* Action structure for actions that do not have any extra data beyond the | |
139 | * action type. */ | |
140 | struct ovnact_null { | |
141 | struct ovnact ovnact; | |
142 | }; | |
143 | ||
c571f48c BP |
144 | /* Logical pipeline in which a set of actions is executed. */ |
145 | enum ovnact_pipeline { | |
146 | OVNACT_P_INGRESS, | |
147 | OVNACT_P_EGRESS, | |
148 | }; | |
149 | ||
ebb467ff | 150 | /* OVNACT_NEXT. */ |
d5a76da4 BP |
151 | struct ovnact_next { |
152 | struct ovnact ovnact; | |
8f5de083 BP |
153 | |
154 | /* Arguments. */ | |
4c99cb18 BP |
155 | uint8_t ltable; /* Logical table ID of next table. */ |
156 | enum ovnact_pipeline pipeline; /* Pipeline of next table. */ | |
8f5de083 BP |
157 | |
158 | /* Information about the flow that the action is in. This does not affect | |
159 | * behavior, since the implementation of "next" doesn't depend on the | |
160 | * source table or pipeline. It does affect how ovnacts_format() prints | |
161 | * the action. */ | |
4c99cb18 BP |
162 | uint8_t src_ltable; /* Logical table ID of source table. */ |
163 | enum ovnact_pipeline src_pipeline; /* Pipeline of source table. */ | |
d5a76da4 BP |
164 | }; |
165 | ||
166 | /* OVNACT_LOAD. */ | |
167 | struct ovnact_load { | |
168 | struct ovnact ovnact; | |
169 | struct expr_field dst; | |
170 | union expr_constant imm; | |
171 | }; | |
172 | ||
173 | /* OVNACT_MOVE, OVNACT_EXCHANGE. */ | |
174 | struct ovnact_move { | |
175 | struct ovnact ovnact; | |
176 | struct expr_field lhs; | |
177 | struct expr_field rhs; | |
178 | }; | |
179 | ||
ebb467ff BP |
180 | /* OVNACT_CT_NEXT. */ |
181 | struct ovnact_ct_next { | |
182 | struct ovnact ovnact; | |
183 | uint8_t ltable; /* Logical table ID of next table. */ | |
184 | }; | |
185 | ||
d5a76da4 BP |
186 | /* OVNACT_CT_COMMIT. */ |
187 | struct ovnact_ct_commit { | |
188 | struct ovnact ovnact; | |
189 | uint32_t ct_mark, ct_mark_mask; | |
190 | ovs_be128 ct_label, ct_label_mask; | |
191 | }; | |
192 | ||
193 | /* OVNACT_CT_DNAT, OVNACT_CT_SNAT. */ | |
194 | struct ovnact_ct_nat { | |
195 | struct ovnact ovnact; | |
196 | ovs_be32 ip; | |
197 | uint8_t ltable; /* Logical table ID of next table. */ | |
198 | }; | |
199 | ||
200 | struct ovnact_ct_lb_dst { | |
201 | ovs_be32 ip; | |
202 | uint16_t port; | |
203 | }; | |
204 | ||
205 | /* OVNACT_CT_LB. */ | |
206 | struct ovnact_ct_lb { | |
207 | struct ovnact ovnact; | |
208 | struct ovnact_ct_lb_dst *dsts; | |
209 | size_t n_dsts; | |
210 | uint8_t ltable; /* Logical table ID of next table. */ | |
211 | }; | |
212 | ||
b3bd2c33 | 213 | /* OVNACT_ARP, OVNACT_ND_NA, OVNACT_CLONE. */ |
d5a76da4 BP |
214 | struct ovnact_nest { |
215 | struct ovnact ovnact; | |
216 | struct ovnact *nested; | |
217 | size_t nested_len; | |
218 | }; | |
219 | ||
220 | /* OVNACT_GET_ARP, OVNACT_GET_ND. */ | |
221 | struct ovnact_get_mac_bind { | |
222 | struct ovnact ovnact; | |
223 | struct expr_field port; /* Logical port name. */ | |
224 | struct expr_field ip; /* 32-bit or 128-bit IP address. */ | |
225 | }; | |
226 | ||
227 | /* OVNACT_PUT_ARP, ONVACT_PUT_ND. */ | |
228 | struct ovnact_put_mac_bind { | |
229 | struct ovnact ovnact; | |
230 | struct expr_field port; /* Logical port name. */ | |
231 | struct expr_field ip; /* 32-bit or 128-bit IP address. */ | |
232 | struct expr_field mac; /* 48-bit Ethernet address. */ | |
233 | }; | |
234 | ||
235 | struct ovnact_dhcp_option { | |
236 | const struct dhcp_opts_map *option; | |
237 | struct expr_constant_set value; | |
238 | }; | |
239 | ||
240 | /* OVNACT_PUT_DHCPV4_OPTS, OVNACT_PUT_DHCPV6_OPTS. */ | |
241 | struct ovnact_put_dhcp_opts { | |
242 | struct ovnact ovnact; | |
243 | struct expr_field dst; /* 1-bit destination field. */ | |
244 | struct ovnact_dhcp_option *options; | |
245 | size_t n_options; | |
246 | }; | |
247 | ||
a6095f81 BS |
248 | /* Valid arguments to SET_QUEUE action. |
249 | * | |
250 | * QDISC_MIN_QUEUE_ID is the default queue, so user-defined queues should | |
251 | * start at QDISC_MIN_QUEUE_ID+1. */ | |
252 | #define QDISC_MIN_QUEUE_ID 0 | |
253 | #define QDISC_MAX_QUEUE_ID 0xf000 | |
254 | ||
255 | /* OVNACT_SET_QUEUE. */ | |
256 | struct ovnact_set_queue { | |
257 | struct ovnact ovnact; | |
258 | uint16_t queue_id; | |
259 | }; | |
260 | ||
d5a76da4 BP |
261 | /* Internal use by the helpers below. */ |
262 | void ovnact_init(struct ovnact *, enum ovnact_type, size_t len); | |
263 | void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len); | |
264 | ||
265 | /* For each OVNACT_<ENUM> with a corresponding struct <STRUCT>, this defines | |
266 | * the following commonly useful functions: | |
267 | * | |
268 | * struct <STRUCT> *ovnact_put_<ENUM>(struct ofpbuf *ovnacts); | |
269 | * | |
270 | * Appends a new 'ovnact', of length OVNACT_<ENUM>_SIZE, to 'ovnacts', | |
271 | * initializes it with ovnact_init_<ENUM>(), and returns it. Also sets | |
272 | * 'ovnacts->header' to the returned action. | |
273 | * | |
274 | * struct <STRUCT> *ovnact_get_<ENUM>(const struct ovnact *ovnact); | |
275 | * | |
276 | * Returns 'ovnact' cast to "struct <STRUCT> *". 'ovnact->type' must be | |
277 | * OVNACT_<ENUM>. | |
278 | * | |
279 | * as well as the following more rarely useful definitions: | |
280 | * | |
281 | * void ovnact_init_<ENUM>(struct <STRUCT> *ovnact); | |
282 | * | |
283 | * Initializes the parts of 'ovnact' that identify it as having type | |
284 | * OVNACT_<ENUM> and length OVNACT_<ENUM>_SIZE and zeros the rest. | |
285 | * | |
286 | * <ENUM>_SIZE | |
287 | * | |
288 | * The size of the action structure, that is, sizeof(struct <STRUCT>) | |
289 | * rounded up to a multiple of OVNACT_ALIGNTO. | |
290 | */ | |
291 | #define OVNACT(ENUM, STRUCT) \ | |
292 | BUILD_ASSERT_DECL(offsetof(struct STRUCT, ovnact) == 0); \ | |
293 | \ | |
294 | enum { OVNACT_##ENUM##_SIZE = OVNACT_ALIGN(sizeof(struct STRUCT)) }; \ | |
295 | \ | |
296 | static inline struct STRUCT * \ | |
297 | ovnact_get_##ENUM(const struct ovnact *ovnact) \ | |
298 | { \ | |
299 | ovs_assert(ovnact->type == OVNACT_##ENUM); \ | |
300 | return ALIGNED_CAST(struct STRUCT *, ovnact); \ | |
301 | } \ | |
302 | \ | |
303 | static inline struct STRUCT * \ | |
304 | ovnact_put_##ENUM(struct ofpbuf *ovnacts) \ | |
305 | { \ | |
306 | return ovnact_put(ovnacts, OVNACT_##ENUM, \ | |
307 | OVNACT_##ENUM##_SIZE); \ | |
308 | } \ | |
309 | \ | |
310 | static inline void \ | |
311 | ovnact_init_##ENUM(struct STRUCT *ovnact) \ | |
312 | { \ | |
313 | ovnact_init(&ovnact->ovnact, OVNACT_##ENUM, \ | |
314 | OVNACT_##ENUM##_SIZE); \ | |
315 | } | |
316 | OVNACTS | |
317 | #undef OVNACT | |
318 | ||
467085fd GS |
319 | #define MAX_OVN_GROUPS 65535 |
320 | ||
321 | struct group_table { | |
322 | unsigned long *group_ids; /* Used as a bitmap with value set | |
323 | * for allocated group ids in either | |
324 | * desired_groups or existing_groups. */ | |
325 | struct hmap desired_groups; | |
326 | struct hmap existing_groups; | |
327 | }; | |
328 | ||
329 | struct group_info { | |
330 | struct hmap_node hmap_node; | |
331 | struct ds group; | |
332 | uint32_t group_id; | |
e4f7cf9c GS |
333 | bool new_group_id; /* 'True' if 'group_id' was reserved from |
334 | * group_table's 'group_ids' bitmap. */ | |
467085fd GS |
335 | }; |
336 | ||
6335d074 BP |
337 | enum action_opcode { |
338 | /* "arp { ...actions... }". | |
339 | * | |
340 | * The actions, in OpenFlow 1.3 format, follow the action_header. | |
341 | */ | |
342 | ACTION_OPCODE_ARP, | |
0bac7164 BP |
343 | |
344 | /* "put_arp(port, ip, mac)" | |
345 | * | |
346 | * Arguments are passed through the packet metadata and data, as follows: | |
347 | * | |
348 | * MFF_REG0 = ip | |
349 | * MFF_LOG_INPORT = port | |
350 | * MFF_ETH_SRC = mac | |
351 | */ | |
352 | ACTION_OPCODE_PUT_ARP, | |
42814145 NS |
353 | |
354 | /* "result = put_dhcp_opts(offer_ip, option, ...)". | |
355 | * | |
356 | * Arguments follow the action_header, in this format: | |
357 | * - A 32-bit or 64-bit OXM header designating the result field. | |
358 | * - A 32-bit integer specifying a bit offset within the result field. | |
359 | * - The 32-bit DHCP offer IP. | |
360 | * - Any number of DHCP options. | |
361 | */ | |
362 | ACTION_OPCODE_PUT_DHCP_OPTS, | |
e75451fe | 363 | |
f8a8db39 | 364 | /* "nd_na { ...actions... }". |
e75451fe ZKL |
365 | * |
366 | * The actions, in OpenFlow 1.3 format, follow the action_header. | |
367 | */ | |
f8a8db39 | 368 | ACTION_OPCODE_ND_NA, |
c34a87b6 JP |
369 | |
370 | /* "put_nd(port, ip6, mac)" | |
371 | * | |
372 | * Arguments are passed through the packet metadata and data, as follows: | |
373 | * | |
374 | * MFF_XXREG0 = ip6 | |
375 | * MFF_LOG_INPORT = port | |
376 | * MFF_ETH_SRC = mac | |
377 | */ | |
378 | ACTION_OPCODE_PUT_ND, | |
01cfdb2f NS |
379 | |
380 | /* "result = put_dhcpv6_opts(option, ...)". | |
381 | * | |
382 | * Arguments follow the action_header, in this format: | |
383 | * - A 32-bit or 64-bit OXM header designating the result field. | |
384 | * - A 32-bit integer specifying a bit offset within the result field. | |
385 | * - Any number of DHCPv6 options. | |
386 | */ | |
387 | ACTION_OPCODE_PUT_DHCPV6_OPTS, | |
6335d074 BP |
388 | }; |
389 | ||
390 | /* Header. */ | |
391 | struct action_header { | |
392 | ovs_be32 opcode; /* One of ACTION_OPCODE_* */ | |
393 | uint8_t pad[4]; | |
394 | }; | |
395 | BUILD_ASSERT_DECL(sizeof(struct action_header) == 8); | |
396 | ||
d5a76da4 | 397 | struct ovnact_parse_params { |
1d7b2ece BP |
398 | /* A table of "struct expr_symbol"s to support (as one would provide to |
399 | * expr_parse()). */ | |
400 | const struct shash *symtab; | |
401 | ||
d5a76da4 | 402 | /* hmap of 'struct dhcp_opts_map' to support 'put_dhcp_opts' action */ |
42814145 NS |
403 | const struct hmap *dhcp_opts; |
404 | ||
01cfdb2f NS |
405 | /* hmap of 'struct dhcp_opts_map' to support 'put_dhcpv6_opts' action */ |
406 | const struct hmap *dhcpv6_opts; | |
407 | ||
4c99cb18 BP |
408 | /* Each OVN flow exists in a logical table within a logical pipeline. |
409 | * These parameters express this context for a set of OVN actions being | |
410 | * parsed: | |
d5a76da4 | 411 | * |
4c99cb18 BP |
412 | * - 'n_tables' is the number of tables in the logical ingress and |
413 | * egress pipelines, that is, "next" may specify a table less than | |
414 | * or equal to 'n_tables'. If 'n_tables' is 0 then "next" is | |
415 | * disallowed entirely. | |
d5a76da4 | 416 | * |
4c99cb18 BP |
417 | * - 'cur_ltable' is the logical table of the current flow, within |
418 | * 'pipeline'. If cur_ltable + 1 < n_tables, then this defines the | |
419 | * default table that "next" will jump to. | |
420 | * | |
421 | * - 'pipeline' is the logical pipeline. It is the default pipeline to | |
422 | * which 'next' will jump. If 'pipeline' is OVNACT_P_EGRESS, then | |
423 | * 'next' will also be able to jump into the ingress pipeline, but | |
424 | * the reverse is not true. */ | |
425 | enum ovnact_pipeline pipeline; /* Logical pipeline. */ | |
426 | uint8_t n_tables; /* Number of logical flow tables. */ | |
427 | uint8_t cur_ltable; /* 0 <= cur_ltable < n_tables. */ | |
d5a76da4 BP |
428 | }; |
429 | ||
9aef3c1b BP |
430 | bool ovnacts_parse(struct lexer *, const struct ovnact_parse_params *, |
431 | struct ofpbuf *ovnacts, struct expr **prereqsp); | |
d5a76da4 BP |
432 | char *ovnacts_parse_string(const char *s, const struct ovnact_parse_params *, |
433 | struct ofpbuf *ovnacts, struct expr **prereqsp) | |
434 | OVS_WARN_UNUSED_RESULT; | |
435 | ||
436 | void ovnacts_format(const struct ovnact[], size_t ovnacts_len, struct ds *); | |
437 | ||
438 | struct ovnact_encode_params { | |
f1c16a85 BP |
439 | /* Looks up logical port 'port_name'. If found, stores its port number in |
440 | * '*portp' and returns true; otherwise, returns false. */ | |
441 | bool (*lookup_port)(const void *aux, const char *port_name, | |
442 | unsigned int *portp); | |
443 | const void *aux; | |
1d7b2ece | 444 | |
c2e954a1 GS |
445 | /* 'true' if the flow is for a switch. */ |
446 | bool is_switch; | |
447 | ||
1b441300 MS |
448 | /* 'true' if the flow is for a gateway router. */ |
449 | bool is_gateway_router; | |
450 | ||
467085fd GS |
451 | /* A struct to figure out the group_id for group actions. */ |
452 | struct group_table *group_table; | |
453 | ||
1d7b2ece BP |
454 | /* OVN maps each logical flow table (ltable), one-to-one, onto a physical |
455 | * OpenFlow flow table (ptable). A number of parameters describe this | |
456 | * mapping and data related to flow tables: | |
457 | * | |
4c99cb18 BP |
458 | * - 'pipeline' is the logical pipeline in which the actions are |
459 | * executing. | |
1d7b2ece | 460 | * |
4c99cb18 BP |
461 | * - 'ingress_ptable' is the OpenFlow table that corresponds to OVN |
462 | * ingress table 0. | |
463 | * | |
464 | * - 'egress_ptable' is the OpenFlow table that corresponds to OVN | |
465 | * egress table 0. | |
1d7b2ece BP |
466 | * |
467 | * - 'output_ptable' should be the OpenFlow table to which the logical | |
4c99cb18 BP |
468 | * "output" action will resubmit. |
469 | * | |
470 | * - 'mac_bind_ptable' should be the OpenFlow table used to track MAC | |
471 | * bindings. */ | |
472 | enum ovnact_pipeline pipeline; /* Logical pipeline. */ | |
473 | uint8_t ingress_ptable; /* First OpenFlow ingress table. */ | |
474 | uint8_t egress_ptable; /* First OpenFlow egress table. */ | |
1d7b2ece | 475 | uint8_t output_ptable; /* OpenFlow table for 'output' to resubmit. */ |
c34a87b6 JP |
476 | uint8_t mac_bind_ptable; /* OpenFlow table for 'get_arp'/'get_nd' to |
477 | resubmit. */ | |
1d7b2ece BP |
478 | }; |
479 | ||
d5a76da4 BP |
480 | void ovnacts_encode(const struct ovnact[], size_t ovnacts_len, |
481 | const struct ovnact_encode_params *, | |
482 | struct ofpbuf *ofpacts); | |
483 | ||
484 | void ovnacts_free(struct ovnact[], size_t ovnacts_len); | |
3b7cb7e1 BP |
485 | |
486 | #endif /* ovn/actions.h */ |