Branch data Line data Source code
1 : : /* Copyright (c) 2015, 2016 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 "binding.h"
18 : : #include "lflow.h"
19 : : #include "lport.h"
20 : :
21 : : #include "lib/bitmap.h"
22 : : #include "lib/poll-loop.h"
23 : : #include "lib/sset.h"
24 : : #include "lib/util.h"
25 : : #include "lib/vswitch-idl.h"
26 : : #include "openvswitch/hmap.h"
27 : : #include "openvswitch/vlog.h"
28 : : #include "ovn/lib/ovn-sb-idl.h"
29 : : #include "ovn-controller.h"
30 : :
31 : 94 : VLOG_DEFINE_THIS_MODULE(binding);
32 : :
33 : : void
34 : 44 : binding_register_ovs_idl(struct ovsdb_idl *ovs_idl)
35 : : {
36 : 44 : ovsdb_idl_add_table(ovs_idl, &ovsrec_table_open_vswitch);
37 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_open_vswitch_col_bridges);
38 : :
39 : 44 : ovsdb_idl_add_table(ovs_idl, &ovsrec_table_bridge);
40 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_name);
41 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_bridge_col_ports);
42 : :
43 : 44 : ovsdb_idl_add_table(ovs_idl, &ovsrec_table_port);
44 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_name);
45 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_port_col_interfaces);
46 : :
47 : 44 : ovsdb_idl_add_table(ovs_idl, &ovsrec_table_interface);
48 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_name);
49 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_external_ids);
50 : 44 : ovsdb_idl_add_column(ovs_idl, &ovsrec_interface_col_ingress_policing_rate);
51 : 44 : ovsdb_idl_add_column(ovs_idl,
52 : : &ovsrec_interface_col_ingress_policing_burst);
53 : 44 : }
54 : :
55 : : static void
56 : 3163 : get_local_iface_ids(const struct ovsrec_bridge *br_int,
57 : : struct shash *lport_to_iface,
58 : : struct sset *all_lports)
59 : : {
60 : : int i;
61 : :
62 [ + + ]: 47426 : for (i = 0; i < br_int->n_ports; i++) {
63 : 44263 : const struct ovsrec_port *port_rec = br_int->ports[i];
64 : : const char *iface_id;
65 : : int j;
66 : :
67 [ + + ]: 44263 : if (!strcmp(port_rec->name, br_int->name)) {
68 : 3163 : continue;
69 : : }
70 : :
71 [ + + ]: 82200 : for (j = 0; j < port_rec->n_interfaces; j++) {
72 : : const struct ovsrec_interface *iface_rec;
73 : :
74 : 41100 : iface_rec = port_rec->interfaces[j];
75 : 41100 : iface_id = smap_get(&iface_rec->external_ids, "iface-id");
76 [ + + ]: 41100 : if (!iface_id) {
77 : 28216 : continue;
78 : : }
79 : 12884 : shash_add(lport_to_iface, iface_id, iface_rec);
80 : 12884 : sset_add(all_lports, iface_id);
81 : : }
82 : : }
83 : 3163 : }
84 : :
85 : : static void
86 : 13085 : add_local_datapath(struct hmap *local_datapaths,
87 : : const struct sbrec_port_binding *binding_rec)
88 : : {
89 [ + + ]: 13085 : if (get_local_datapath(local_datapaths,
90 : 13085 : binding_rec->datapath->tunnel_key)) {
91 : 7907 : return;
92 : : }
93 : :
94 : 5178 : struct local_datapath *ld = xzalloc(sizeof *ld);
95 : 5178 : ld->logical_port = xstrdup(binding_rec->logical_port);
96 : 5178 : memcpy(&ld->uuid, &binding_rec->header_.uuid, sizeof ld->uuid);
97 : 5178 : hmap_insert(local_datapaths, &ld->hmap_node,
98 : : binding_rec->datapath->tunnel_key);
99 : : }
100 : :
101 : : static void
102 : 12255 : update_qos(const struct ovsrec_interface *iface_rec,
103 : : const struct sbrec_port_binding *pb)
104 : : {
105 : 12255 : int rate = smap_get_int(&pb->options, "policing_rate", 0);
106 : 12255 : int burst = smap_get_int(&pb->options, "policing_burst", 0);
107 : :
108 : 12255 : ovsrec_interface_set_ingress_policing_rate(iface_rec, MAX(0, rate));
109 : 12255 : ovsrec_interface_set_ingress_policing_burst(iface_rec, MAX(0, burst));
110 : 12255 : }
111 : :
112 : : static void
113 : 62676 : consider_local_datapath(struct controller_ctx *ctx,
114 : : const struct sbrec_chassis *chassis_rec,
115 : : const struct sbrec_port_binding *binding_rec,
116 : : struct hmap *local_datapaths,
117 : : struct shash *lport_to_iface,
118 : : struct sset *all_lports)
119 : : {
120 : 62676 : const struct ovsrec_interface *iface_rec
121 : 62676 : = shash_find_data(lport_to_iface, binding_rec->logical_port);
122 : :
123 [ + + ]: 62676 : if (iface_rec
124 [ + + ]: 50241 : || (binding_rec->parent_port && binding_rec->parent_port[0] &&
[ - + # # ]
125 : 0 : sset_contains(all_lports, binding_rec->parent_port))) {
126 [ - + ][ # # ]: 12435 : if (binding_rec->parent_port && binding_rec->parent_port[0]) {
127 : : /* Add child logical port to the set of all local ports. */
128 : 0 : sset_add(all_lports, binding_rec->logical_port);
129 : : }
130 : 12435 : add_local_datapath(local_datapaths, binding_rec);
131 [ + - ][ + + ]: 12435 : if (iface_rec && ctx->ovs_idl_txn) {
132 : 12255 : update_qos(iface_rec, binding_rec);
133 : : }
134 [ + + ]: 12435 : if (binding_rec->chassis == chassis_rec) {
135 : 12295 : return;
136 : : }
137 [ + + ]: 252 : if (ctx->ovnsb_idl_txn) {
138 [ - + ]: 112 : if (binding_rec->chassis) {
139 [ # # ]: 0 : VLOG_INFO("Changing chassis for lport %s from %s to %s.",
140 : : binding_rec->logical_port,
141 : : binding_rec->chassis->name,
142 : : chassis_rec->name);
143 : : } else {
144 [ + - ]: 112 : VLOG_INFO("Claiming lport %s for this chassis.",
145 : : binding_rec->logical_port);
146 : : }
147 : 112 : sbrec_port_binding_set_chassis(binding_rec, chassis_rec);
148 : : }
149 [ - + ]: 50241 : } else if (!strcmp(binding_rec->type, "l2gateway")) {
150 : 0 : const char *chassis_id = smap_get(&binding_rec->options,
151 : : "l2gateway-chassis");
152 [ # # ][ # # ]: 0 : if (!chassis_id || strcmp(chassis_id, chassis_rec->name)) {
153 [ # # ][ # # ]: 0 : if (binding_rec->chassis == chassis_rec && ctx->ovnsb_idl_txn) {
154 [ # # ]: 0 : VLOG_INFO("Releasing l2gateway port %s from this chassis.",
155 : : binding_rec->logical_port);
156 : 0 : sbrec_port_binding_set_chassis(binding_rec, NULL);
157 : : }
158 : 0 : return;
159 : : }
160 : :
161 : 0 : sset_add(all_lports, binding_rec->logical_port);
162 : 0 : add_local_datapath(local_datapaths, binding_rec);
163 [ # # ]: 0 : if (binding_rec->chassis == chassis_rec) {
164 : 0 : return;
165 : : }
166 : :
167 [ # # ][ # # ]: 0 : if (!strcmp(chassis_id, chassis_rec->name) && ctx->ovnsb_idl_txn) {
168 [ # # ]: 0 : VLOG_INFO("Claiming l2gateway port %s for this chassis.",
169 : : binding_rec->logical_port);
170 : 0 : sbrec_port_binding_set_chassis(binding_rec, chassis_rec);
171 : : }
172 [ + + ]: 50241 : } else if (!strcmp(binding_rec->type, "l3gateway")) {
173 : 928 : const char *chassis = smap_get(&binding_rec->options,
174 : : "l3gateway-chassis");
175 [ + + ][ + + ]: 928 : if (!strcmp(chassis, chassis_rec->name) && ctx->ovnsb_idl_txn) {
176 : 928 : add_local_datapath(local_datapaths, binding_rec);
177 : : }
178 [ + - ][ + + ]: 49313 : } else if (chassis_rec && binding_rec->chassis == chassis_rec) {
179 [ + + ]: 10 : if (ctx->ovnsb_idl_txn) {
180 [ + - ]: 4 : VLOG_INFO("Releasing lport %s from this chassis.",
181 : : binding_rec->logical_port);
182 : 4 : sbrec_port_binding_set_chassis(binding_rec, NULL);
183 : 4 : sset_find_and_delete(all_lports, binding_rec->logical_port);
184 : : }
185 [ + + ]: 49307 : } else if (!binding_rec->chassis
186 [ + + ]: 29650 : && !strcmp(binding_rec->type, "localnet")) {
187 : : /* Add all localnet ports to all_lports so that we allocate ct zones
188 : : * for them. */
189 : 716 : sset_add(all_lports, binding_rec->logical_port);
190 : : }
191 : : }
192 : :
193 : : void
194 : 3167 : binding_run(struct controller_ctx *ctx, const struct ovsrec_bridge *br_int,
195 : : const char *chassis_id, struct hmap *local_datapaths,
196 : : struct sset *all_lports)
197 : : {
198 : : const struct sbrec_chassis *chassis_rec;
199 : : const struct sbrec_port_binding *binding_rec;
200 : 3167 : struct shash lport_to_iface = SHASH_INITIALIZER(&lport_to_iface);
201 : :
202 : 3167 : chassis_rec = get_chassis(ctx->ovnsb_idl, chassis_id);
203 [ + + ]: 3167 : if (!chassis_rec) {
204 : 4 : return;
205 : : }
206 : :
207 [ + - ]: 3163 : if (br_int) {
208 : 3163 : get_local_iface_ids(br_int, &lport_to_iface, all_lports);
209 : : }
210 : :
211 : : /* Run through each binding record to see if it is resident on this
212 : : * chassis and update the binding accordingly. This includes both
213 : : * directly connected logical ports and children of those ports. */
214 [ + + ]: 65839 : SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
215 : 62676 : consider_local_datapath(ctx, chassis_rec, binding_rec,
216 : : local_datapaths, &lport_to_iface,
217 : : all_lports);
218 : : }
219 : :
220 : 3163 : shash_destroy(&lport_to_iface);
221 : : }
222 : :
223 : : /* Returns true if the database is all cleaned up, false if more work is
224 : : * required. */
225 : : bool
226 : 138 : binding_cleanup(struct controller_ctx *ctx, const char *chassis_id)
227 : : {
228 [ + + ]: 138 : if (!ctx->ovnsb_idl_txn) {
229 : 44 : return false;
230 : : }
231 : :
232 [ - + ]: 94 : if (!chassis_id) {
233 : 0 : return true;
234 : : }
235 : :
236 : 94 : const struct sbrec_chassis *chassis_rec
237 : 94 : = get_chassis(ctx->ovnsb_idl, chassis_id);
238 [ + + ]: 94 : if (!chassis_rec) {
239 : 50 : return true;
240 : : }
241 : :
242 : 44 : ovsdb_idl_txn_add_comment(
243 : : ctx->ovnsb_idl_txn,
244 : : "ovn-controller: removing all port bindings for '%s'", chassis_id);
245 : :
246 : : const struct sbrec_port_binding *binding_rec;
247 : 44 : bool any_changes = false;
248 [ + + ]: 458 : SBREC_PORT_BINDING_FOR_EACH(binding_rec, ctx->ovnsb_idl) {
249 [ + + ]: 414 : if (binding_rec->chassis == chassis_rec) {
250 : 128 : sbrec_port_binding_set_chassis(binding_rec, NULL);
251 : 128 : any_changes = true;
252 : : }
253 : : }
254 : 44 : return !any_changes;
255 : : }
|