]>
git.proxmox.com Git - mirror_ovs.git/blob - ovn/controller-vtep/binding.c
1 /* Copyright (c) 2015 Nicira, Inc.
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "lib/shash.h"
22 #include "openvswitch/vlog.h"
23 #include "ovn-controller-vtep.h"
24 #include "ovn/lib/ovn-sb-idl.h"
25 #include "vtep/vtep-idl.h"
27 VLOG_DEFINE_THIS_MODULE(binding
);
30 * This module scans through the Port_Binding table in ovnsb. If there is a
31 * logical port binding entry for logical switch in vtep gateway chassis's
32 * 'vtep_logical_switches' column, sets the binding's chassis column to the
33 * corresponding vtep gateway chassis.
38 /* Returns true if the 'vtep_lswitch' specified in 'port_binding_rec'
39 * has already been bound to another port binding entry, and resets
40 * 'port_binding_rec''s chassis column. Otherwise, updates 'ls_to_pb'
41 * and returns false. */
43 check_pb_conflict(struct shash
*ls_to_pb
,
44 const struct sbrec_port_binding
*port_binding_rec
,
45 const char *chassis_name
,
46 const char *vtep_lswitch
)
48 const struct sbrec_port_binding
*pb_conflict
=
49 shash_find_data(ls_to_pb
, vtep_lswitch
);
52 VLOG_WARN("logical switch (%s), on vtep gateway chassis "
53 "(%s) has already been associated with logical "
54 "port (%s), ignore logical port (%s)",
55 vtep_lswitch
, chassis_name
,
56 pb_conflict
->logical_port
,
57 port_binding_rec
->logical_port
);
58 sbrec_port_binding_set_chassis(port_binding_rec
, NULL
);
63 shash_add(ls_to_pb
, vtep_lswitch
, port_binding_rec
);
67 /* Returns true if the 'vtep_lswitch' specified in 'port_binding_rec'
68 * has already been bound to a different datapath, and resets
69 * 'port_binding_rec''s chassis column. Otherwise, updates 'ls_to_db' and
72 check_db_conflict(struct shash
*ls_to_db
,
73 const struct sbrec_port_binding
*port_binding_rec
,
74 const char *chassis_name
,
75 const char *vtep_lswitch
)
77 const struct sbrec_datapath_binding
*db_conflict
=
78 shash_find_data(ls_to_db
, vtep_lswitch
);
80 if (db_conflict
&& db_conflict
!= port_binding_rec
->datapath
) {
81 VLOG_WARN("logical switch (%s), on vtep gateway chassis "
82 "(%s) has already been associated with logical "
83 "datapath (with tunnel key %"PRId64
"), ignore "
84 "logical port (%s) which belongs to logical "
85 "datapath (with tunnel key %"PRId64
")",
86 vtep_lswitch
, chassis_name
,
87 db_conflict
->tunnel_key
,
88 port_binding_rec
->logical_port
,
89 port_binding_rec
->datapath
->tunnel_key
);
90 sbrec_port_binding_set_chassis(port_binding_rec
, NULL
);
95 shash_replace(ls_to_db
, vtep_lswitch
, port_binding_rec
->datapath
);
99 /* Updates the 'port_binding_rec''s chassis column to 'chassis_rec'. */
101 update_pb_chassis(const struct sbrec_port_binding
*port_binding_rec
,
102 const struct sbrec_chassis
*chassis_rec
)
104 if (port_binding_rec
->chassis
!= chassis_rec
) {
105 if (chassis_rec
&& port_binding_rec
->chassis
) {
106 VLOG_DBG("Changing chassis association of logical "
107 "port (%s) from (%s) to (%s)",
108 port_binding_rec
->logical_port
,
109 port_binding_rec
->chassis
->name
,
112 sbrec_port_binding_set_chassis(port_binding_rec
, chassis_rec
);
117 /* Checks and updates logical port to vtep logical switch bindings for each
118 * physical switch in VTEP. */
120 binding_run(struct controller_vtep_ctx
*ctx
)
122 if (!ctx
->ovnsb_idl_txn
) {
128 * Maps vtep logical switch name to the datapath binding entry. This is
129 * used to guarantee that each vtep logical switch is only included
130 * in only one ovn datapath (ovn logical switch). See check_db_conflict()
135 * Maps vtep logical switch name to the port binding entry. This is used
136 * to guarantee that each vtep logical switch on a vtep physical switch
137 * is only bound to one logical port. See check_pb_conflict() for
141 struct shash ls_to_db
= SHASH_INITIALIZER(&ls_to_db
);
143 /* Stores the 'chassis' and the 'ls_to_pb' map related to
144 * a vtep physcial switch. */
146 const struct sbrec_chassis
*chassis_rec
;
147 struct shash ls_to_pb
;
149 struct shash ps_map
= SHASH_INITIALIZER(&ps_map
);
150 const struct vteprec_physical_switch
*pswitch
;
151 VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch
, ctx
->vtep_idl
) {
152 const struct sbrec_chassis
*chassis_rec
153 = get_chassis_by_name(ctx
->ovnsb_idl
, pswitch
->name
);
154 struct ps
*ps
= xmalloc(sizeof *ps
);
157 /* 'chassis_rec' must exist. */
158 ovs_assert(chassis_rec
);
159 ps
->chassis_rec
= chassis_rec
;
160 shash_init(&ps
->ls_to_pb
);
161 for (i
= 0; i
< chassis_rec
->n_vtep_logical_switches
; i
++) {
162 shash_add(&ps
->ls_to_pb
, chassis_rec
->vtep_logical_switches
[i
],
165 shash_add(&ps_map
, chassis_rec
->name
, ps
);
168 ovsdb_idl_txn_add_comment(ctx
->ovnsb_idl_txn
,
169 "ovn-controller-vtep: updating bindings");
171 const struct sbrec_port_binding
*port_binding_rec
;
172 /* Port binding for vtep gateway chassis must have type "vtep",
173 * and matched physical switch name and logical switch name. */
174 SBREC_PORT_BINDING_FOR_EACH(port_binding_rec
, ctx
->ovnsb_idl
) {
175 const char *type
= port_binding_rec
->type
;
176 const char *vtep_pswitch
= smap_get(&port_binding_rec
->options
,
177 "vtep-physical-switch");
178 const char *vtep_lswitch
= smap_get(&port_binding_rec
->options
,
179 "vtep-logical-switch");
181 = vtep_pswitch
? shash_find_data(&ps_map
, vtep_pswitch
) : NULL
;
183 = ps
&& vtep_lswitch
&& shash_find(&ps
->ls_to_pb
, vtep_lswitch
);
185 if (!strcmp(type
, "vtep") && found_ls
) {
186 bool pb_conflict
, db_conflict
;
188 pb_conflict
= check_pb_conflict(&ps
->ls_to_pb
, port_binding_rec
,
189 ps
->chassis_rec
->name
,
191 db_conflict
= check_db_conflict(&ls_to_db
, port_binding_rec
,
192 ps
->chassis_rec
->name
,
194 /* Updates port binding's chassis column when there
196 if (!pb_conflict
&& !db_conflict
) {
197 update_pb_chassis(port_binding_rec
, ps
->chassis_rec
);
199 } else if (port_binding_rec
->chassis
200 && shash_find(&ps_map
, port_binding_rec
->chassis
->name
)) {
201 /* Resets 'port_binding_rec' since it is no longer bound to
202 * any vtep logical switch. */
203 update_pb_chassis(port_binding_rec
, NULL
);
207 struct shash_node
*iter
, *next
;
208 SHASH_FOR_EACH_SAFE (iter
, next
, &ps_map
) {
209 struct ps
*ps
= iter
->data
;
210 struct shash_node
*node
;
212 SHASH_FOR_EACH (node
, &ps
->ls_to_pb
) {
214 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 5);
215 VLOG_DBG_RL(&rl
, "No port binding entry for logical switch (%s)"
216 "on vtep gateway chassis (%s)", node
->name
,
217 ps
->chassis_rec
->name
);
220 shash_delete(&ps_map
, iter
);
221 shash_destroy(&ps
->ls_to_pb
);
224 shash_destroy(&ls_to_db
);
225 shash_destroy(&ps_map
);
228 /* Removes all port binding association with vtep gateway chassis.
229 * Returns true when done (i.e. there is no change made to 'ctx->ovnsb_idl'),
230 * otherwise returns false. */
232 binding_cleanup(struct controller_vtep_ctx
*ctx
)
234 if (!ctx
->ovnsb_idl_txn
) {
238 struct shash ch_to_pb
= SHASH_INITIALIZER(&ch_to_pb
);
239 const struct sbrec_port_binding
*port_binding_rec
;
240 bool all_done
= true;
241 /* Hashs all port binding entries using the associated chassis name. */
242 SBREC_PORT_BINDING_FOR_EACH(port_binding_rec
, ctx
->ovnsb_idl
) {
243 if (port_binding_rec
->chassis
) {
244 shash_add(&ch_to_pb
, port_binding_rec
->chassis
->name
,
249 ovsdb_idl_txn_add_comment(ctx
->ovnsb_idl_txn
,
250 "ovn-controller-vtep: removing bindings");
252 const struct vteprec_physical_switch
*pswitch
;
253 VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch
, ctx
->vtep_idl
) {
254 const struct sbrec_chassis
*chassis_rec
255 = get_chassis_by_name(ctx
->ovnsb_idl
, pswitch
->name
);
262 port_binding_rec
= shash_find_and_delete(&ch_to_pb
,
264 if (!port_binding_rec
) {
268 update_pb_chassis(port_binding_rec
, NULL
);
271 shash_destroy(&ch_to_pb
);