ovn: Adopt consistent naming, by renaming "Bindings" to "Binding".
[cascardo/ovs.git] / ovn / controller / physical.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 "physical.h"
18 #include "match.h"
19 #include "ofctrl.h"
20 #include "ofp-actions.h"
21 #include "ofpbuf.h"
22 #include "ovn-controller.h"
23 #include "ovn/lib/ovn-sb-idl.h"
24 #include "pipeline.h"
25 #include "simap.h"
26 #include "vswitch-idl.h"
27
28 void
29 physical_init(struct controller_ctx *ctx)
30 {
31     ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_bridge);
32     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_bridge_col_ports);
33
34     ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_port);
35     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_name);
36     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_interfaces);
37     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_port_col_external_ids);
38
39     ovsdb_idl_add_table(ctx->ovs_idl, &ovsrec_table_interface);
40     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_name);
41     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_ofport);
42     ovsdb_idl_add_column(ctx->ovs_idl, &ovsrec_interface_col_external_ids);
43 }
44
45 void
46 physical_run(struct controller_ctx *ctx)
47 {
48     struct simap lport_to_ofport = SIMAP_INITIALIZER(&lport_to_ofport);
49     struct simap chassis_to_ofport = SIMAP_INITIALIZER(&chassis_to_ofport);
50     for (int i = 0; i < ctx->br_int->n_ports; i++) {
51         const struct ovsrec_port *port_rec = ctx->br_int->ports[i];
52         if (!strcmp(port_rec->name, ctx->br_int_name)) {
53             continue;
54         }
55
56         const char *chassis_id = smap_get(&port_rec->external_ids,
57                                           "ovn-chassis-id");
58         if (chassis_id && !strcmp(chassis_id, ctx->chassis_id)) {
59             continue;
60         }
61
62         for (int j = 0; j < port_rec->n_interfaces; j++) {
63             const struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
64
65             /* Get OpenFlow port number. */
66             if (!iface_rec->n_ofport) {
67                 continue;
68             }
69             int64_t ofport = iface_rec->ofport[0];
70             if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) {
71                 continue;
72             }
73
74             /* Record as chassis or local logical port. */
75             if (chassis_id) {
76                 simap_put(&chassis_to_ofport, chassis_id, ofport);
77                 break;
78             } else {
79                 const char *iface_id = smap_get(&iface_rec->external_ids,
80                                                 "iface-id");
81                 if (iface_id) {
82                     simap_put(&lport_to_ofport, iface_id, ofport);
83                 }
84             }
85         }
86     }
87
88     struct ofpbuf ofpacts;
89     ofpbuf_init(&ofpacts, 0);
90
91     /* Set up flows in table 0 for physical-to-logical translation and in table
92      * 64 for logical-to-physical translation. */
93     const struct sbrec_binding *binding;
94     SBREC_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
95         /* Find the Openflow port for the logical port, as 'ofport'.  If it's
96          * on a remote chassis, this is the OpenFlow port for the tunnel to
97          * that chassis (and set 'local' to false).  Otherwise, if it's on the
98          * chassis we're managing, this is the OpenFlow port for the vif itself
99          * (and set 'local' to true). */
100         ofp_port_t ofport = u16_to_ofp(simap_get(&lport_to_ofport,
101                                                  binding->logical_port));
102         bool local = ofport != 0;
103         if (!local) {
104             ofport = u16_to_ofp(simap_get(&chassis_to_ofport,
105                                           binding->chassis));
106             if (!ofport) {
107                 continue;
108             }
109         }
110
111         /* Translate the logical datapath into the form we use in
112          * MFF_METADATA. */
113         uint32_t ldp = ldp_to_integer(&binding->logical_datapath);
114         if (!ldp) {
115             continue;
116         }
117
118         struct match match;
119         if (local) {
120             /* Table 0, Priority 100.
121              * ======================
122              *
123              * For packets that arrive from a vif: set MFF_LOG_INPORT to the
124              * logical input port, MFF_METADATA to the logical datapath, and
125              * resubmit into the logical pipeline starting at table 16. */
126             match_init_catchall(&match);
127             ofpbuf_clear(&ofpacts);
128             match_set_in_port(&match, ofport);
129
130             /* Set MFF_METADATA. */
131             struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
132             sf->field = mf_from_id(MFF_METADATA);
133             sf->value.be64 = htonll(ldp);
134             sf->mask.be64 = OVS_BE64_MAX;
135
136             /* Set MFF_LOG_INPORT. */
137             sf = ofpact_put_SET_FIELD(&ofpacts);
138             sf->field = mf_from_id(MFF_LOG_INPORT);
139             sf->value.be32 = htonl(binding->tunnel_key);
140             sf->mask.be32 = OVS_BE32_MAX;
141
142             /* Resubmit to first logical pipeline table. */
143             struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
144             resubmit->in_port = OFPP_IN_PORT;
145             resubmit->table_id = 16;
146             ofctrl_add_flow(0, 100, &match, &ofpacts);
147
148             /* Table 0, Priority 50.
149              * =====================
150              *
151              * For packets that arrive from a remote node destined to this
152              * local vif: deliver directly to the vif. */
153             match_init_catchall(&match);
154             ofpbuf_clear(&ofpacts);
155             match_set_tun_id(&match, htonll(binding->tunnel_key));
156             ofpact_put_OUTPUT(&ofpacts)->port = ofport;
157             ofctrl_add_flow(0, 50, &match, &ofpacts);
158         }
159
160         /* Table 64, Priority 100.
161          * =======================
162          *
163          * Drop packets whose logical inport and outport are the same. */
164         match_init_catchall(&match);
165         ofpbuf_clear(&ofpacts);
166         match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, binding->tunnel_key);
167         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, binding->tunnel_key);
168         ofctrl_add_flow(64, 100, &match, &ofpacts);
169
170         /* Table 64, Priority 50.
171          * ======================
172          *
173          * For packets to remote machines, send them over a tunnel to the
174          * remote chassis.
175          *
176          * For packets to local vifs, deliver them directly. */
177         match_init_catchall(&match);
178         ofpbuf_clear(&ofpacts);
179         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, binding->tunnel_key);
180         if (!local) {
181             /* Set MFF_TUN_ID. */
182             struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
183             sf->field = mf_from_id(MFF_TUN_ID);
184             sf->value.be64 = htonll(binding->tunnel_key);
185             sf->mask.be64 = OVS_BE64_MAX;
186         }
187         ofpact_put_OUTPUT(&ofpacts)->port = ofport;
188         ofctrl_add_flow(64, 50, &match, &ofpacts);
189     }
190
191     ofpbuf_uninit(&ofpacts);
192     simap_destroy(&lport_to_ofport);
193     simap_destroy(&chassis_to_ofport);
194 }