ovn-controller: Pass 'br_int' explicitly to functions that need it.
[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, const struct ovsrec_bridge *br_int,
47              struct hmap *flow_table)
48 {
49     struct simap lport_to_ofport = SIMAP_INITIALIZER(&lport_to_ofport);
50     struct simap chassis_to_ofport = SIMAP_INITIALIZER(&chassis_to_ofport);
51     for (int i = 0; i < br_int->n_ports; i++) {
52         const struct ovsrec_port *port_rec = br_int->ports[i];
53         if (!strcmp(port_rec->name, br_int->name)) {
54             continue;
55         }
56
57         const char *chassis_id = smap_get(&port_rec->external_ids,
58                                           "ovn-chassis-id");
59         if (chassis_id && !strcmp(chassis_id, ctx->chassis_id)) {
60             continue;
61         }
62
63         for (int j = 0; j < port_rec->n_interfaces; j++) {
64             const struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
65
66             /* Get OpenFlow port number. */
67             if (!iface_rec->n_ofport) {
68                 continue;
69             }
70             int64_t ofport = iface_rec->ofport[0];
71             if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) {
72                 continue;
73             }
74
75             /* Record as chassis or local logical port. */
76             if (chassis_id) {
77                 simap_put(&chassis_to_ofport, chassis_id, ofport);
78                 break;
79             } else {
80                 const char *iface_id = smap_get(&iface_rec->external_ids,
81                                                 "iface-id");
82                 if (iface_id) {
83                     simap_put(&lport_to_ofport, iface_id, ofport);
84                 }
85             }
86         }
87     }
88
89     struct ofpbuf ofpacts;
90     ofpbuf_init(&ofpacts, 0);
91
92     /* Set up flows in table 0 for physical-to-logical translation and in table
93      * 64 for logical-to-physical translation. */
94     const struct sbrec_binding *binding;
95     SBREC_BINDING_FOR_EACH (binding, ctx->ovnsb_idl) {
96         /* Find the OpenFlow port for the logical port, as 'ofport'.  If it's
97          * on a remote chassis, this is the OpenFlow port for the tunnel to
98          * that chassis (and set 'local' to false).  Otherwise, if it's on the
99          * chassis we're managing, this is the OpenFlow port for the vif itself
100          * (and set 'local' to true). When 'parent_port' is set for a binding,
101          * it implies a container sitting inside a VM reachable via a 'tag'.
102          */
103
104         int tag = 0;
105         ofp_port_t ofport;
106         if (binding->parent_port) {
107             ofport = u16_to_ofp(simap_get(&lport_to_ofport,
108                                           binding->parent_port));
109             if (ofport && binding->tag) {
110                 tag = *binding->tag;
111             }
112         } else {
113             ofport = u16_to_ofp(simap_get(&lport_to_ofport,
114                                           binding->logical_port));
115         }
116
117         bool local = ofport != 0;
118         if (!local) {
119             if (!binding->chassis) {
120                 continue;
121             }
122             ofport = u16_to_ofp(simap_get(&chassis_to_ofport,
123                                           binding->chassis->name));
124             if (!ofport) {
125                 continue;
126             }
127         }
128
129         /* Translate the logical datapath into the form we use in
130          * MFF_METADATA. */
131         uint32_t ldp = ldp_to_integer(&binding->logical_datapath);
132         if (!ldp) {
133             continue;
134         }
135
136         struct match match;
137         if (local) {
138             /* Packets that arrive from a vif can belong to a VM or
139              * to a container located inside that VM. Packets that
140              * arrive from containers have a tag (vlan) associated with them.
141              */
142
143             /* Table 0, Priority 150 and 100.
144              * ==============================
145              *
146              * Priority 150 is for traffic belonging to containers. For such
147              * traffic, match on the tags and then strip the tag.
148              * Priority 100 is for traffic belonging to VMs.
149              *
150              * For both types of traffic: set MFF_LOG_INPORT to the
151              * logical input port, MFF_METADATA to the logical datapath, and
152              * resubmit into the logical pipeline starting at table 16. */
153             match_init_catchall(&match);
154             ofpbuf_clear(&ofpacts);
155             match_set_in_port(&match, ofport);
156             if (tag) {
157                 match_set_dl_vlan(&match, htons(tag));
158             }
159
160             /* Set MFF_METADATA. */
161             struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
162             sf->field = mf_from_id(MFF_METADATA);
163             sf->value.be64 = htonll(ldp);
164             sf->mask.be64 = OVS_BE64_MAX;
165
166             /* Set MFF_LOG_INPORT. */
167             sf = ofpact_put_SET_FIELD(&ofpacts);
168             sf->field = mf_from_id(MFF_LOG_INPORT);
169             sf->value.be32 = htonl(binding->tunnel_key);
170             sf->mask.be32 = OVS_BE32_MAX;
171
172             /* Strip vlans. */
173             if (tag) {
174                 ofpact_put_STRIP_VLAN(&ofpacts);
175             }
176
177             /* Resubmit to first logical pipeline table. */
178             struct ofpact_resubmit *resubmit = ofpact_put_RESUBMIT(&ofpacts);
179             resubmit->in_port = OFPP_IN_PORT;
180             resubmit->table_id = 16;
181             ofctrl_add_flow(flow_table, 0, tag ? 150 : 100, &match, &ofpacts);
182
183             /* Table 0, Priority 50.
184              * =====================
185              *
186              * For packets that arrive from a remote node destined to this
187              * local vif: deliver directly to the vif. If the destination
188              * is a container sitting behind a vif, tag the packets. */
189             match_init_catchall(&match);
190             ofpbuf_clear(&ofpacts);
191             match_set_tun_id(&match, htonll(binding->tunnel_key));
192             if (tag) {
193                 struct ofpact_vlan_vid *vlan_vid;
194                 vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts);
195                 vlan_vid->vlan_vid = tag;
196                 vlan_vid->push_vlan_if_needed = true;
197             }
198             ofpact_put_OUTPUT(&ofpacts)->port = ofport;
199             ofctrl_add_flow(flow_table, 0, 50, &match, &ofpacts);
200         }
201
202         /* Table 64, Priority 100.
203          * =======================
204          *
205          * Drop packets whose logical inport and outport are the same. */
206         match_init_catchall(&match);
207         ofpbuf_clear(&ofpacts);
208         match_set_reg(&match, MFF_LOG_INPORT - MFF_REG0, binding->tunnel_key);
209         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, binding->tunnel_key);
210         ofctrl_add_flow(flow_table, 64, 100, &match, &ofpacts);
211
212         /* Table 64, Priority 50.
213          * ======================
214          *
215          * For packets to remote machines, send them over a tunnel to the
216          * remote chassis.
217          *
218          * For packets to local vifs, deliver them directly. */
219         match_init_catchall(&match);
220         ofpbuf_clear(&ofpacts);
221         match_set_reg(&match, MFF_LOG_OUTPORT - MFF_REG0, binding->tunnel_key);
222         if (!local) {
223             /* Set MFF_TUN_ID. */
224             struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
225             sf->field = mf_from_id(MFF_TUN_ID);
226             sf->value.be64 = htonll(binding->tunnel_key);
227             sf->mask.be64 = OVS_BE64_MAX;
228         }
229         if (tag) {
230             /* For containers sitting behind a local vif, tag the packets
231              * before delivering them. Since there is a possibility of
232              * packets needing to hair-pin back into the same vif from
233              * which it came, make the in_port as zero. */
234             struct ofpact_vlan_vid *vlan_vid;
235             vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts);
236             vlan_vid->vlan_vid = tag;
237             vlan_vid->push_vlan_if_needed = true;
238
239             struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
240             sf->field = mf_from_id(MFF_IN_PORT);
241             sf->value.be16 = 0;
242             sf->mask.be16 = OVS_BE16_MAX;
243         }
244         ofpact_put_OUTPUT(&ofpacts)->port = ofport;
245         ofctrl_add_flow(flow_table, 64, 50, &match, &ofpacts);
246     }
247
248     ofpbuf_uninit(&ofpacts);
249     simap_destroy(&lport_to_ofport);
250     simap_destroy(&chassis_to_ofport);
251 }