]> git.proxmox.com Git - ovs.git/blob - ovn/controller/physical.c
ovn: Rename Binding table to Port_Binding.
[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_register_ovs_idl(struct ovsdb_idl *ovs_idl)
30 {
31 ovsdb_idl_add_table(ovs_idl, &ovsrec_table_bridge);
32 ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_ports);
33
34 ovsdb_idl_add_table(ovs_idl, &ovsrec_table_port);
35 ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_name);
36 ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_interfaces);
37 ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_external_ids);
38
39 ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface);
40 ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_name);
41 ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_ofport);
42 ovsdb_idl_add_column(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 const char *this_chassis_id, 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, this_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_port_binding *binding;
95 SBREC_PORT_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, push the in_port to stack and make the
234 * in_port as zero. */
235 struct ofpact_vlan_vid *vlan_vid;
236 vlan_vid = ofpact_put_SET_VLAN_VID(&ofpacts);
237 vlan_vid->vlan_vid = tag;
238 vlan_vid->push_vlan_if_needed = true;
239
240 struct ofpact_stack *stack_action;
241 const struct mf_field *field;
242 stack_action = ofpact_put_STACK_PUSH(&ofpacts);
243 field = mf_from_id(MFF_IN_PORT);
244 stack_action->subfield.field = field;
245 stack_action->subfield.ofs = 0;
246 stack_action->subfield.n_bits = field->n_bits;
247
248 struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);
249 sf->field = mf_from_id(MFF_IN_PORT);
250 sf->value.be16 = 0;
251 sf->mask.be16 = OVS_BE16_MAX;
252 }
253 ofpact_put_OUTPUT(&ofpacts)->port = ofport;
254 if (tag) {
255 /* Revert the tag added to the packets headed to containers
256 * in the previous step. If we don't do this, the packets
257 * that are to be broadcasted to a VM in the same logical
258 * switch will also contain the tag. Also revert the zero'd
259 * in_port. */
260 ofpact_put_STRIP_VLAN(&ofpacts);
261
262 struct ofpact_stack *stack_action;
263 const struct mf_field *field;
264 stack_action = ofpact_put_STACK_POP(&ofpacts);
265 field = mf_from_id(MFF_IN_PORT);
266 stack_action->subfield.field = field;
267 stack_action->subfield.ofs = 0;
268 stack_action->subfield.n_bits = field->n_bits;
269 }
270 ofctrl_add_flow(flow_table, 64, 50, &match, &ofpacts);
271 }
272
273 ofpbuf_uninit(&ofpacts);
274 simap_destroy(&lport_to_ofport);
275 simap_destroy(&chassis_to_ofport);
276 }