]> git.proxmox.com Git - ovs.git/blob - ovn/controller/lflow.c
ovn: Extend logical "next" action to jump to arbitrary flow tables.
[ovs.git] / ovn / controller / lflow.c
1 /* Copyright (c) 2015 Nicira, Inc.
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <config.h>
17 #include "lflow.h"
18 #include "dynamic-string.h"
19 #include "ofctrl.h"
20 #include "ofp-actions.h"
21 #include "ofpbuf.h"
22 #include "openvswitch/vlog.h"
23 #include "ovn/controller/ovn-controller.h"
24 #include "ovn/lib/actions.h"
25 #include "ovn/lib/expr.h"
26 #include "ovn/lib/ovn-sb-idl.h"
27 #include "simap.h"
28
29 VLOG_DEFINE_THIS_MODULE(lflow);
30 \f
31 /* Symbol table. */
32
33 /* Contains "struct expr_symbol"s for fields supported by OVN lflows. */
34 static struct shash symtab;
35
36 static void
37 add_logical_register(struct shash *symtab, enum mf_field_id id)
38 {
39 char name[8];
40
41 snprintf(name, sizeof name, "reg%d", id - MFF_REG0);
42 expr_symtab_add_field(symtab, name, id, NULL, false);
43 }
44
45 static void
46 symtab_init(void)
47 {
48 shash_init(&symtab);
49
50 /* Reserve a pair of registers for the logical inport and outport. A full
51 * 32-bit register each is bigger than we need, but the expression code
52 * doesn't yet support string fields that occupy less than a full OXM. */
53 expr_symtab_add_string(&symtab, "inport", MFF_LOG_INPORT, NULL);
54 expr_symtab_add_string(&symtab, "outport", MFF_LOG_OUTPORT, NULL);
55
56 /* Logical registers. */
57 #define MFF_LOG_REG(ID) add_logical_register(&symtab, ID);
58 MFF_LOG_REGS;
59 #undef MFF_LOG_REG
60
61 /* Data fields. */
62 expr_symtab_add_field(&symtab, "eth.src", MFF_ETH_SRC, NULL, false);
63 expr_symtab_add_field(&symtab, "eth.dst", MFF_ETH_DST, NULL, false);
64 expr_symtab_add_field(&symtab, "eth.type", MFF_ETH_TYPE, NULL, true);
65
66 expr_symtab_add_field(&symtab, "vlan.tci", MFF_VLAN_TCI, NULL, false);
67 expr_symtab_add_predicate(&symtab, "vlan.present", "vlan.tci[12]");
68 expr_symtab_add_subfield(&symtab, "vlan.pcp", "vlan.present",
69 "vlan.tci[13..15]");
70 expr_symtab_add_subfield(&symtab, "vlan.vid", "vlan.present",
71 "vlan.tci[0..11]");
72
73 expr_symtab_add_predicate(&symtab, "ip4", "eth.type == 0x800");
74 expr_symtab_add_predicate(&symtab, "ip6", "eth.type == 0x86dd");
75 expr_symtab_add_predicate(&symtab, "ip", "ip4 || ip6");
76 expr_symtab_add_field(&symtab, "ip.proto", MFF_IP_PROTO, "ip", true);
77 expr_symtab_add_field(&symtab, "ip.dscp", MFF_IP_DSCP, "ip", false);
78 expr_symtab_add_field(&symtab, "ip.ecn", MFF_IP_ECN, "ip", false);
79 expr_symtab_add_field(&symtab, "ip.ttl", MFF_IP_TTL, "ip", false);
80
81 expr_symtab_add_field(&symtab, "ip4.src", MFF_IPV4_SRC, "ip4", false);
82 expr_symtab_add_field(&symtab, "ip4.dst", MFF_IPV4_DST, "ip4", false);
83
84 expr_symtab_add_predicate(&symtab, "icmp4", "ip4 && ip.proto == 1");
85 expr_symtab_add_field(&symtab, "icmp4.type", MFF_ICMPV4_TYPE, "icmp4",
86 false);
87 expr_symtab_add_field(&symtab, "icmp4.code", MFF_ICMPV4_CODE, "icmp4",
88 false);
89
90 expr_symtab_add_field(&symtab, "ip6.src", MFF_IPV6_SRC, "ip6", false);
91 expr_symtab_add_field(&symtab, "ip6.dst", MFF_IPV6_DST, "ip6", false);
92 expr_symtab_add_field(&symtab, "ip6.label", MFF_IPV6_LABEL, "ip6", false);
93
94 expr_symtab_add_predicate(&symtab, "icmp6", "ip6 && ip.proto == 58");
95 expr_symtab_add_field(&symtab, "icmp6.type", MFF_ICMPV6_TYPE, "icmp6",
96 true);
97 expr_symtab_add_field(&symtab, "icmp6.code", MFF_ICMPV6_CODE, "icmp6",
98 true);
99
100 expr_symtab_add_predicate(&symtab, "icmp", "icmp4 || icmp6");
101
102 expr_symtab_add_field(&symtab, "ip.frag", MFF_IP_FRAG, "ip", false);
103 expr_symtab_add_predicate(&symtab, "ip.is_frag", "ip.frag[0]");
104 expr_symtab_add_predicate(&symtab, "ip.later_frag", "ip.frag[1]");
105 expr_symtab_add_predicate(&symtab, "ip.first_frag",
106 "ip.is_frag && !ip.later_frag");
107
108 expr_symtab_add_predicate(&symtab, "arp", "eth.type == 0x806");
109 expr_symtab_add_field(&symtab, "arp.op", MFF_ARP_OP, "arp", false);
110 expr_symtab_add_field(&symtab, "arp.spa", MFF_ARP_SPA, "arp", false);
111 expr_symtab_add_field(&symtab, "arp.sha", MFF_ARP_SHA, "arp", false);
112 expr_symtab_add_field(&symtab, "arp.tpa", MFF_ARP_TPA, "arp", false);
113 expr_symtab_add_field(&symtab, "arp.tha", MFF_ARP_THA, "arp", false);
114
115 expr_symtab_add_predicate(&symtab, "nd",
116 "icmp6.type == {135, 136} && icmp6.code == 0");
117 expr_symtab_add_field(&symtab, "nd.target", MFF_ND_TARGET, "nd", false);
118 expr_symtab_add_field(&symtab, "nd.sll", MFF_ND_SLL,
119 "nd && icmp6.type == 135", false);
120 expr_symtab_add_field(&symtab, "nd.tll", MFF_ND_TLL,
121 "nd && icmp6.type == 136", false);
122
123 expr_symtab_add_predicate(&symtab, "tcp", "ip.proto == 6");
124 expr_symtab_add_field(&symtab, "tcp.src", MFF_TCP_SRC, "tcp", false);
125 expr_symtab_add_field(&symtab, "tcp.dst", MFF_TCP_DST, "tcp", false);
126 expr_symtab_add_field(&symtab, "tcp.flags", MFF_TCP_FLAGS, "tcp", false);
127
128 expr_symtab_add_predicate(&symtab, "udp", "ip.proto == 17");
129 expr_symtab_add_field(&symtab, "udp.src", MFF_UDP_SRC, "udp", false);
130 expr_symtab_add_field(&symtab, "udp.dst", MFF_UDP_DST, "udp", false);
131
132 expr_symtab_add_predicate(&symtab, "sctp", "ip.proto == 132");
133 expr_symtab_add_field(&symtab, "sctp.src", MFF_SCTP_SRC, "sctp", false);
134 expr_symtab_add_field(&symtab, "sctp.dst", MFF_SCTP_DST, "sctp", false);
135 }
136 \f
137 /* Logical datapaths and logical port numbers. */
138
139 /* A logical datapath.
140 *
141 * 'ports' maps 'logical_port' names to 'tunnel_key' values in the OVN_SB
142 * Port_Binding table within the logical datapath. */
143 struct logical_datapath {
144 struct hmap_node hmap_node; /* Indexed on 'uuid'. */
145 struct uuid uuid; /* UUID from Datapath_Binding row. */
146 uint32_t tunnel_key; /* 'tunnel_key' from Datapath_Binding row. */
147 struct simap ports; /* Logical port name to port number. */
148 };
149
150 /* Contains "struct logical_datapath"s. */
151 static struct hmap logical_datapaths = HMAP_INITIALIZER(&logical_datapaths);
152
153 /* Finds and returns the logical_datapath for 'binding', or NULL if no such
154 * logical_datapath exists. */
155 static struct logical_datapath *
156 ldp_lookup(const struct sbrec_datapath_binding *binding)
157 {
158 struct logical_datapath *ldp;
159 HMAP_FOR_EACH_IN_BUCKET (ldp, hmap_node, uuid_hash(&binding->header_.uuid),
160 &logical_datapaths) {
161 if (uuid_equals(&ldp->uuid, &binding->header_.uuid)) {
162 return ldp;
163 }
164 }
165 return NULL;
166 }
167
168 /* Creates a new logical_datapath for the given 'binding'. */
169 static struct logical_datapath *
170 ldp_create(const struct sbrec_datapath_binding *binding)
171 {
172 struct logical_datapath *ldp;
173
174 ldp = xmalloc(sizeof *ldp);
175 hmap_insert(&logical_datapaths, &ldp->hmap_node,
176 uuid_hash(&binding->header_.uuid));
177 ldp->uuid = binding->header_.uuid;
178 ldp->tunnel_key = binding->tunnel_key;
179 simap_init(&ldp->ports);
180 return ldp;
181 }
182
183 static struct logical_datapath *
184 ldp_lookup_or_create(const struct sbrec_datapath_binding *binding)
185 {
186 struct logical_datapath *ldp = ldp_lookup(binding);
187 return ldp ? ldp : ldp_create(binding);
188 }
189
190 static void
191 ldp_free(struct logical_datapath *ldp)
192 {
193 simap_destroy(&ldp->ports);
194 hmap_remove(&logical_datapaths, &ldp->hmap_node);
195 free(ldp);
196 }
197
198 /* Iterates through all of the records in the Port_Binding table, updating the
199 * table of logical_datapaths to match the values found in active
200 * Port_Bindings. */
201 static void
202 ldp_run(struct controller_ctx *ctx)
203 {
204 struct logical_datapath *ldp;
205 HMAP_FOR_EACH (ldp, hmap_node, &logical_datapaths) {
206 simap_clear(&ldp->ports);
207 }
208
209 const struct sbrec_port_binding *binding;
210 SBREC_PORT_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
211 struct logical_datapath *ldp = ldp_lookup_or_create(binding->datapath);
212
213 simap_put(&ldp->ports, binding->logical_port, binding->tunnel_key);
214 }
215
216 const struct sbrec_multicast_group *mc;
217 SBREC_MULTICAST_GROUP_FOR_EACH (mc, ctx->ovnsb_idl) {
218 struct logical_datapath *ldp = ldp_lookup_or_create(mc->datapath);
219 simap_put(&ldp->ports, mc->name, mc->tunnel_key);
220 }
221
222 struct logical_datapath *next_ldp;
223 HMAP_FOR_EACH_SAFE (ldp, next_ldp, hmap_node, &logical_datapaths) {
224 if (simap_is_empty(&ldp->ports)) {
225 ldp_free(ldp);
226 }
227 }
228 }
229
230 static void
231 ldp_destroy(void)
232 {
233 struct logical_datapath *ldp, *next_ldp;
234 HMAP_FOR_EACH_SAFE (ldp, next_ldp, hmap_node, &logical_datapaths) {
235 ldp_free(ldp);
236 }
237 }
238 \f
239 void
240 lflow_init(void)
241 {
242 symtab_init();
243 }
244
245 /* Translates logical flows in the Logical_Flow table in the OVN_SB database
246 * into OpenFlow flows. See ovn-architecture(7) for more information. */
247 void
248 lflow_run(struct controller_ctx *ctx, struct hmap *flow_table)
249 {
250 struct hmap flows = HMAP_INITIALIZER(&flows);
251 uint32_t conj_id_ofs = 1;
252
253 ldp_run(ctx);
254
255 const struct sbrec_logical_flow *lflow;
256 SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->ovnsb_idl) {
257 /* Find the "struct logical_datapath" asssociated with this
258 * Logical_Flow row. If there's no such struct, that must be because
259 * no logical ports are bound to that logical datapath, so there's no
260 * point in maintaining any flows for it anyway, so skip it. */
261 const struct logical_datapath *ldp;
262 ldp = ldp_lookup(lflow->logical_datapath);
263 if (!ldp) {
264 continue;
265 }
266
267 /* Determine translation of logical table IDs to physical table IDs. */
268 bool ingress = !strcmp(lflow->pipeline, "ingress");
269 uint8_t first_ptable = (ingress
270 ? OFTABLE_LOG_INGRESS_PIPELINE
271 : OFTABLE_LOG_EGRESS_PIPELINE);
272 uint8_t ptable = first_ptable + lflow->table_id;
273 uint8_t output_ptable = (ingress
274 ? OFTABLE_REMOTE_OUTPUT
275 : OFTABLE_LOG_TO_PHY);
276
277 /* Translate OVN actions into OpenFlow actions.
278 *
279 * XXX Deny changes to 'outport' in egress pipeline. */
280 uint64_t ofpacts_stub[64 / 8];
281 struct ofpbuf ofpacts;
282 struct expr *prereqs;
283 char *error;
284
285 ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
286 error = actions_parse_string(lflow->actions, &symtab, &ldp->ports,
287 first_ptable, LOG_PIPELINE_LEN,
288 lflow->table_id, output_ptable,
289 &ofpacts, &prereqs);
290 if (error) {
291 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
292 VLOG_WARN_RL(&rl, "error parsing actions \"%s\": %s",
293 lflow->actions, error);
294 free(error);
295 continue;
296 }
297
298 /* Translate OVN match into table of OpenFlow matches. */
299 struct hmap matches;
300 struct expr *expr;
301
302 expr = expr_parse_string(lflow->match, &symtab, &error);
303 if (!error) {
304 if (prereqs) {
305 expr = expr_combine(EXPR_T_AND, expr, prereqs);
306 prereqs = NULL;
307 }
308 expr = expr_annotate(expr, &symtab, &error);
309 }
310 if (error) {
311 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
312 VLOG_WARN_RL(&rl, "error parsing match \"%s\": %s",
313 lflow->match, error);
314 expr_destroy(prereqs);
315 ofpbuf_uninit(&ofpacts);
316 free(error);
317 continue;
318 }
319
320 expr = expr_simplify(expr);
321 expr = expr_normalize(expr);
322 uint32_t n_conjs = expr_to_matches(expr, &ldp->ports, &matches);
323 expr_destroy(expr);
324
325 /* Prepare the OpenFlow matches for adding to the flow table. */
326 struct expr_match *m;
327 HMAP_FOR_EACH (m, hmap_node, &matches) {
328 match_set_metadata(&m->match, htonll(ldp->tunnel_key));
329 if (m->match.wc.masks.conj_id) {
330 m->match.flow.conj_id += conj_id_ofs;
331 }
332 if (!m->n) {
333 ofctrl_add_flow(flow_table, ptable, lflow->priority,
334 &m->match, &ofpacts);
335 } else {
336 uint64_t conj_stubs[64 / 8];
337 struct ofpbuf conj;
338
339 ofpbuf_use_stub(&conj, conj_stubs, sizeof conj_stubs);
340 for (int i = 0; i < m->n; i++) {
341 const struct cls_conjunction *src = &m->conjunctions[i];
342 struct ofpact_conjunction *dst;
343
344 dst = ofpact_put_CONJUNCTION(&conj);
345 dst->id = src->id + conj_id_ofs;
346 dst->clause = src->clause;
347 dst->n_clauses = src->n_clauses;
348 }
349 ofctrl_add_flow(flow_table, ptable, lflow->priority,
350 &m->match, &conj);
351 ofpbuf_uninit(&conj);
352 }
353 }
354
355 /* Clean up. */
356 expr_matches_destroy(&matches);
357 ofpbuf_uninit(&ofpacts);
358 conj_id_ofs += n_conjs;
359 }
360 }
361
362 void
363 lflow_destroy(void)
364 {
365 expr_symtab_destroy(&symtab);
366 ldp_destroy();
367 }