]>
Commit | Line | Data |
---|---|---|
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 | 34 | VLOG_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 |
39 | static struct shash symtab; |
40 | ||
bce7cf45 BP |
41 | void |
42 | lflow_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 | 49 | static void |
a1491e40 BP |
50 | update_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 |
61 | struct 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 |
67 | static 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 |
79 | static bool |
80 | lookup_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 | 101 | static bool |
bce7cf45 | 102 | is_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 |
109 | static void |
110 | add_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 |
147 | static void |
148 | consider_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 |
296 | static void |
297 | put_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 | 308 | static void |
fdbdb595 | 309 | consider_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. */ | |
360 | static void | |
361 | add_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. */ | |
373 | void | |
374 | lflow_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 | 392 | void |
48605550 | 393 | lflow_destroy(void) |
678729a2 BP |
394 | { |
395 | expr_symtab_destroy(&symtab); | |
c775160f | 396 | shash_destroy(&symtab); |
678729a2 | 397 | } |