]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/controller/lflow.c
ovn-controller: Tie OpenFlow and logical flows using OpenFlow cookie.
[mirror_ovs.git] / ovn / controller / lflow.c
CommitLineData
bce7cf45 1/* Copyright (c) 2015, 2016 Nicira, Inc.
678729a2
BP
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>
48605550 17#include "lflow.h"
bce7cf45 18#include "lport.h"
b4e87a48 19#include "ofctrl.h"
b598f214
BW
20#include "openvswitch/dynamic-string.h"
21#include "openvswitch/ofp-actions.h"
64c96779 22#include "openvswitch/ofpbuf.h"
678729a2 23#include "openvswitch/vlog.h"
bce7cf45 24#include "ovn-controller.h"
8b2ed684
AR
25#include "ovn/actions.h"
26#include "ovn/expr.h"
42814145 27#include "ovn/lib/ovn-dhcp.h"
678729a2 28#include "ovn/lib/ovn-sb-idl.h"
aa68cf38 29#include "packets.h"
70c7cfef 30#include "physical.h"
678729a2 31#include "simap.h"
ea382567 32#include "sset.h"
678729a2 33
48605550 34VLOG_DEFINE_THIS_MODULE(lflow);
678729a2
BP
35\f
36/* Symbol table. */
37
48605550 38/* Contains "struct expr_symbol"s for fields supported by OVN lflows. */
678729a2
BP
39static struct shash symtab;
40
bce7cf45
BP
41void
42lflow_init(void)
678729a2 43{
7700eea0 44 ovn_init_symtab(&symtab);
ea382567
RB
45}
46
a1491e40
BP
47/* Iterate address sets in the southbound database. Create and update the
48 * corresponding symtab entries as necessary. */
ea382567 49static void
a1491e40
BP
50update_address_sets(struct controller_ctx *ctx,
51 struct shash *expr_address_sets_p)
ea382567 52
ea382567 53{
a1491e40
BP
54 const struct sbrec_address_set *as;
55 SBREC_ADDRESS_SET_FOR_EACH (as, ctx->ovnsb_idl) {
56 expr_macros_add(expr_address_sets_p, as->name,
57 (const char *const *) as->addresses, as->n_addresses);
ea382567 58 }
ea382567 59}
678729a2 60\f
bce7cf45
BP
61struct lookup_port_aux {
62 const struct lport_index *lports;
63 const struct mcgroup_index *mcgroups;
64 const struct sbrec_datapath_binding *dp;
678729a2
BP
65};
66
a53d69c9
RM
67static void consider_logical_flow(const struct lport_index *lports,
68 const struct mcgroup_index *mcgroups,
69 const struct sbrec_logical_flow *lflow,
70 const struct hmap *local_datapaths,
467085fd 71 struct group_table *group_table,
a53d69c9
RM
72 const struct simap *ct_zones,
73 struct hmap *dhcp_opts_p,
01cfdb2f 74 struct hmap *dhcpv6_opts_p,
926c34fd 75 uint32_t *conj_id_ofs_p,
a1491e40
BP
76 struct hmap *flow_table,
77 struct shash *expr_address_sets_p);
a53d69c9 78
bce7cf45
BP
79static bool
80lookup_port_cb(const void *aux_, const char *port_name, unsigned int *portp)
678729a2 81{
bce7cf45 82 const struct lookup_port_aux *aux = aux_;
678729a2 83
bce7cf45
BP
84 const struct sbrec_port_binding *pb
85 = lport_lookup_by_name(aux->lports, port_name);
86 if (pb && pb->datapath == aux->dp) {
87 *portp = pb->tunnel_key;
88 return true;
678729a2
BP
89 }
90
bce7cf45
BP
91 const struct sbrec_multicast_group *mg
92 = mcgroup_lookup_by_dp_name(aux->mcgroups, aux->dp, port_name);
93 if (mg) {
94 *portp = mg->tunnel_key;
95 return true;
678729a2
BP
96 }
97
bce7cf45 98 return false;
678729a2
BP
99}
100
f1c16a85 101static bool
bce7cf45 102is_switch(const struct sbrec_datapath_binding *ldp)
f1c16a85 103{
bce7cf45
BP
104 return smap_get(&ldp->external_ids, "logical-switch") != NULL;
105
f1c16a85
BP
106}
107
fdbdb595 108/* Adds the logical flows from the Logical_Flow table to flow tables. */
0bac7164
BP
109static void
110add_logical_flows(struct controller_ctx *ctx, const struct lport_index *lports,
111 const struct mcgroup_index *mcgroups,
112 const struct hmap *local_datapaths,
467085fd 113 struct group_table *group_table,
926c34fd 114 const struct simap *ct_zones,
a1491e40
BP
115 struct hmap *flow_table,
116 struct shash *expr_address_sets_p)
678729a2 117{
678729a2 118 uint32_t conj_id_ofs = 1;
70c7cfef
RM
119 const struct sbrec_logical_flow *lflow;
120
42814145 121 struct hmap dhcp_opts = HMAP_INITIALIZER(&dhcp_opts);
01cfdb2f 122 struct hmap dhcpv6_opts = HMAP_INITIALIZER(&dhcpv6_opts);
42814145
NS
123 const struct sbrec_dhcp_options *dhcp_opt_row;
124 SBREC_DHCP_OPTIONS_FOR_EACH(dhcp_opt_row, ctx->ovnsb_idl) {
125 dhcp_opt_add(&dhcp_opts, dhcp_opt_row->name, dhcp_opt_row->code,
126 dhcp_opt_row->type);
127 }
128
01cfdb2f
NS
129
130 const struct sbrec_dhcpv6_options *dhcpv6_opt_row;
131 SBREC_DHCPV6_OPTIONS_FOR_EACH(dhcpv6_opt_row, ctx->ovnsb_idl) {
132 dhcp_opt_add(&dhcpv6_opts, dhcpv6_opt_row->name, dhcpv6_opt_row->code,
133 dhcpv6_opt_row->type);
134 }
135
926c34fd
RM
136 SBREC_LOGICAL_FLOW_FOR_EACH (lflow, ctx->ovnsb_idl) {
137 consider_logical_flow(lports, mcgroups, lflow, local_datapaths,
1ea9b847 138 group_table, ct_zones,
926c34fd 139 &dhcp_opts, &dhcpv6_opts, &conj_id_ofs,
a1491e40 140 flow_table, expr_address_sets_p);
a53d69c9 141 }
bce7cf45 142
a53d69c9 143 dhcp_opts_destroy(&dhcp_opts);
01cfdb2f 144 dhcp_opts_destroy(&dhcpv6_opts);
a53d69c9 145}
b1e04512 146
a53d69c9
RM
147static void
148consider_logical_flow(const struct lport_index *lports,
149 const struct mcgroup_index *mcgroups,
150 const struct sbrec_logical_flow *lflow,
151 const struct hmap *local_datapaths,
467085fd 152 struct group_table *group_table,
a53d69c9
RM
153 const struct simap *ct_zones,
154 struct hmap *dhcp_opts_p,
01cfdb2f 155 struct hmap *dhcpv6_opts_p,
926c34fd 156 uint32_t *conj_id_ofs_p,
a1491e40
BP
157 struct hmap *flow_table,
158 struct shash *expr_address_sets_p)
a53d69c9
RM
159{
160 /* Determine translation of logical table IDs to physical table IDs. */
161 bool ingress = !strcmp(lflow->pipeline, "ingress");
558ec83d 162
a53d69c9
RM
163 const struct sbrec_datapath_binding *ldp = lflow->logical_datapath;
164 if (!ldp) {
165 return;
166 }
1ea9b847
BP
167 if (!get_local_datapath(local_datapaths, ldp->tunnel_key)) {
168 return;
a53d69c9 169 }
678729a2 170
a53d69c9
RM
171 /* Determine translation of logical table IDs to physical table IDs. */
172 uint8_t first_ptable = (ingress
173 ? OFTABLE_LOG_INGRESS_PIPELINE
174 : OFTABLE_LOG_EGRESS_PIPELINE);
175 uint8_t ptable = first_ptable + lflow->table_id;
176 uint8_t output_ptable = (ingress
177 ? OFTABLE_REMOTE_OUTPUT
bf143492 178 : OFTABLE_SAVE_INPORT);
a53d69c9 179
d5a76da4 180 /* Parse OVN logical actions.
a53d69c9
RM
181 *
182 * XXX Deny changes to 'outport' in egress pipeline. */
d5a76da4
BP
183 uint64_t ovnacts_stub[1024 / 8];
184 struct ofpbuf ovnacts = OFPBUF_STUB_INITIALIZER(ovnacts_stub);
185 struct ovnact_parse_params pp = {
186 .symtab = &symtab,
187 .dhcp_opts = dhcp_opts_p,
188 .dhcpv6_opts = dhcpv6_opts_p,
189
190 .n_tables = LOG_PIPELINE_LEN,
191 .cur_ltable = lflow->table_id,
192 };
a53d69c9
RM
193 struct expr *prereqs;
194 char *error;
195
d5a76da4
BP
196 error = ovnacts_parse_string(lflow->actions, &pp, &ovnacts, &prereqs);
197 if (error) {
198 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
199 VLOG_WARN_RL(&rl, "error parsing actions \"%s\": %s",
200 lflow->actions, error);
201 free(error);
ce81a73f 202 ovnacts_free(ovnacts.data, ovnacts.size);
d5a76da4
BP
203 ofpbuf_uninit(&ovnacts);
204 return;
205 }
206
207 /* Encode OVN logical actions into OpenFlow. */
208 uint64_t ofpacts_stub[1024 / 8];
209 struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
a53d69c9
RM
210 struct lookup_port_aux aux = {
211 .lports = lports,
212 .mcgroups = mcgroups,
213 .dp = lflow->logical_datapath
214 };
d5a76da4 215 struct ovnact_encode_params ep = {
a53d69c9
RM
216 .lookup_port = lookup_port_cb,
217 .aux = &aux,
c2e954a1 218 .is_switch = is_switch(ldp),
a53d69c9 219 .ct_zones = ct_zones,
467085fd 220 .group_table = group_table,
a53d69c9 221
a53d69c9 222 .first_ptable = first_ptable,
a53d69c9 223 .output_ptable = output_ptable,
c34a87b6 224 .mac_bind_ptable = OFTABLE_MAC_BINDING,
a53d69c9 225 };
d5a76da4 226 ovnacts_encode(ovnacts.data, ovnacts.size, &ep, &ofpacts);
ce81a73f 227 ovnacts_free(ovnacts.data, ovnacts.size);
d5a76da4 228 ofpbuf_uninit(&ovnacts);
678729a2 229
a53d69c9
RM
230 /* Translate OVN match into table of OpenFlow matches. */
231 struct hmap matches;
232 struct expr *expr;
233
234 expr = expr_parse_string(lflow->match, &symtab,
a1491e40 235 expr_address_sets_p, &error);
a53d69c9
RM
236 if (!error) {
237 if (prereqs) {
238 expr = expr_combine(EXPR_T_AND, expr, prereqs);
239 prereqs = NULL;
678729a2 240 }
a53d69c9
RM
241 expr = expr_annotate(expr, &symtab, &error);
242 }
243 if (error) {
244 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
245 VLOG_WARN_RL(&rl, "error parsing match \"%s\": %s",
246 lflow->match, error);
247 expr_destroy(prereqs);
248 ofpbuf_uninit(&ofpacts);
249 free(error);
250 return;
251 }
678729a2 252
a53d69c9
RM
253 expr = expr_simplify(expr);
254 expr = expr_normalize(expr);
255 uint32_t n_conjs = expr_to_matches(expr, lookup_port_cb, &aux,
256 &matches);
257 expr_destroy(expr);
258
259 /* Prepare the OpenFlow matches for adding to the flow table. */
260 struct expr_match *m;
261 HMAP_FOR_EACH (m, hmap_node, &matches) {
262 match_set_metadata(&m->match,
263 htonll(lflow->logical_datapath->tunnel_key));
264 if (m->match.wc.masks.conj_id) {
265 m->match.flow.conj_id += *conj_id_ofs_p;
266 }
267 if (!m->n) {
c80eac1f
BP
268 ofctrl_add_flow(flow_table, ptable, lflow->priority,
269 lflow->header_.uuid.parts[0], &m->match, &ofpacts);
a53d69c9
RM
270 } else {
271 uint64_t conj_stubs[64 / 8];
272 struct ofpbuf conj;
273
274 ofpbuf_use_stub(&conj, conj_stubs, sizeof conj_stubs);
275 for (int i = 0; i < m->n; i++) {
276 const struct cls_conjunction *src = &m->conjunctions[i];
277 struct ofpact_conjunction *dst;
278
279 dst = ofpact_put_CONJUNCTION(&conj);
280 dst->id = src->id + *conj_id_ofs_p;
281 dst->clause = src->clause;
282 dst->n_clauses = src->n_clauses;
678729a2 283 }
c80eac1f 284 ofctrl_add_flow(flow_table, ptable, lflow->priority, 0, &m->match,
926c34fd 285 &conj);
a53d69c9 286 ofpbuf_uninit(&conj);
678729a2 287 }
678729a2 288 }
42814145 289
a53d69c9
RM
290 /* Clean up. */
291 expr_matches_destroy(&matches);
292 ofpbuf_uninit(&ofpacts);
293 *conj_id_ofs_p += n_conjs;
678729a2
BP
294}
295
0bac7164
BP
296static void
297put_load(const uint8_t *data, size_t len,
298 enum mf_field_id dst, int ofs, int n_bits,
299 struct ofpbuf *ofpacts)
300{
128684a6
JR
301 struct ofpact_set_field *sf = ofpact_put_set_field(ofpacts,
302 mf_from_id(dst), NULL,
303 NULL);
304 bitwise_copy(data, len, 0, sf->value, sf->field->n_bytes, ofs, n_bits);
305 bitwise_one(ofpact_set_field_mask(sf), sf->field->n_bytes, ofs, n_bits);
0bac7164
BP
306}
307
7ecefc49 308static void
fdbdb595 309consider_neighbor_flow(const struct lport_index *lports,
7ecefc49 310 const struct sbrec_mac_binding *b,
926c34fd 311 struct hmap *flow_table)
7ecefc49
RM
312{
313 const struct sbrec_port_binding *pb
314 = lport_lookup_by_name(lports, b->logical_port);
315 if (!pb) {
316 return;
317 }
318
319 struct eth_addr mac;
320 if (!eth_addr_from_string(b->mac, &mac)) {
321 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
322 VLOG_WARN_RL(&rl, "bad 'mac' %s", b->mac);
323 return;
324 }
325
b81e5900 326 struct match match = MATCH_CATCHALL_INITIALIZER;
c34a87b6
JP
327 if (strchr(b->ip, '.')) {
328 ovs_be32 ip;
329 if (!ip_parse(b->ip, &ip)) {
330 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
331 VLOG_WARN_RL(&rl, "bad 'ip' %s", b->ip);
332 return;
333 }
b81e5900 334 match_set_reg(&match, 0, ntohl(ip));
c34a87b6
JP
335 } else {
336 struct in6_addr ip6;
337 if (!ipv6_parse(b->ip, &ip6)) {
338 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
339 VLOG_WARN_RL(&rl, "bad 'ip' %s", b->ip);
340 return;
341 }
342 ovs_be128 value;
343 memcpy(&value, &ip6, sizeof(value));
b81e5900 344 match_set_xxreg(&match, 0, ntoh128(value));
7ecefc49
RM
345 }
346
b81e5900
CSV
347 match_set_metadata(&match, htonll(pb->datapath->tunnel_key));
348 match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, pb->tunnel_key);
7ecefc49 349
b81e5900
CSV
350 uint64_t stub[1024 / 8];
351 struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(stub);
352 put_load(mac.ea, sizeof mac.ea, MFF_ETH_DST, 0, 48, &ofpacts);
c80eac1f 353 ofctrl_add_flow(flow_table, OFTABLE_MAC_BINDING, 100, 0, &match, &ofpacts);
b81e5900 354 ofpbuf_uninit(&ofpacts);
7ecefc49
RM
355}
356
fdbdb595 357/* Adds an OpenFlow flow to flow tables for each MAC binding in the OVN
0bac7164
BP
358 * southbound database, using 'lports' to resolve logical port names to
359 * numbers. */
360static void
361add_neighbor_flows(struct controller_ctx *ctx,
926c34fd
RM
362 const struct lport_index *lports,
363 struct hmap *flow_table)
0bac7164 364{
0bac7164 365 const struct sbrec_mac_binding *b;
926c34fd 366 SBREC_MAC_BINDING_FOR_EACH (b, ctx->ovnsb_idl) {
b81e5900 367 consider_neighbor_flow(lports, b, flow_table);
0bac7164 368 }
0bac7164
BP
369}
370\f
371/* Translates logical flows in the Logical_Flow table in the OVN_SB database
372 * into OpenFlow flows. See ovn-architecture(7) for more information. */
373void
374lflow_run(struct controller_ctx *ctx, const struct lport_index *lports,
375 const struct mcgroup_index *mcgroups,
376 const struct hmap *local_datapaths,
467085fd 377 struct group_table *group_table,
926c34fd
RM
378 const struct simap *ct_zones,
379 struct hmap *flow_table)
0bac7164 380{
a1491e40
BP
381 struct shash expr_address_sets = SHASH_INITIALIZER(&expr_address_sets);
382
383 update_address_sets(ctx, &expr_address_sets);
0bac7164 384 add_logical_flows(ctx, lports, mcgroups, local_datapaths,
1ea9b847 385 group_table, ct_zones, flow_table, &expr_address_sets);
926c34fd 386 add_neighbor_flows(ctx, lports, flow_table);
a1491e40
BP
387
388 expr_macros_destroy(&expr_address_sets);
389 shash_destroy(&expr_address_sets);
0bac7164
BP
390}
391
678729a2 392void
48605550 393lflow_destroy(void)
678729a2
BP
394{
395 expr_symtab_destroy(&symtab);
c775160f 396 shash_destroy(&symtab);
678729a2 397}