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.
22 #include "lib/shash.h"
26 #include "ovn-controller-vtep.h"
27 #include "openvswitch/vlog.h"
28 #include "ovn/lib/ovn-sb-idl.h"
29 #include "vtep/vtep-idl.h"
31 VLOG_DEFINE_THIS_MODULE(vtep);
34 * Scans through the Binding table in ovnsb, and updates the vtep logical
35 * switch tunnel keys and the 'Ucast_Macs_Remote' table in the VTEP
40 /* Searches the 'chassis_rec->encaps' for the first vtep tunnel
41 * configuration, returns the 'ip'. Unless duplicated, the returned
42 * pointer cannot live past current vtep_run() execution. */
44 get_chassis_vtep_ip(const struct sbrec_chassis *chassis_rec)
49 for (i = 0; i < chassis_rec->n_encaps; i++) {
50 if (!strcmp(chassis_rec->encaps[i]->type, "vxlan")) {
51 return chassis_rec->encaps[i]->ip;
59 /* Creates a new 'Ucast_Macs_Remote'. */
60 static struct vteprec_ucast_macs_remote *
61 create_umr(struct ovsdb_idl_txn *vtep_idl_txn, const char *mac,
62 const struct vteprec_logical_switch *vtep_ls)
64 struct vteprec_ucast_macs_remote *new_umr;
66 new_umr = vteprec_ucast_macs_remote_insert(vtep_idl_txn);
67 vteprec_ucast_macs_remote_set_MAC(new_umr, mac);
68 vteprec_ucast_macs_remote_set_logical_switch(new_umr, vtep_ls);
73 /* Creates a new 'Physical_Locator'. */
74 static struct vteprec_physical_locator *
75 create_pl(struct ovsdb_idl_txn *vtep_idl_txn, const char *chassis_ip)
77 struct vteprec_physical_locator *new_pl;
79 new_pl = vteprec_physical_locator_insert(vtep_idl_txn);
80 vteprec_physical_locator_set_dst_ip(new_pl, chassis_ip);
81 vteprec_physical_locator_set_encapsulation_type(new_pl, VTEP_ENCAP_TYPE);
87 /* Updates the vtep Logical_Switch table entries' tunnel keys based
88 * on the port bindings. */
90 vtep_lswitch_run(struct shash *vtep_pbs, struct sset *vtep_pswitches,
91 struct shash *vtep_lswitches)
93 struct sset used_ls = SSET_INITIALIZER(&used_ls);
94 struct shash_node *node;
96 /* Collects the logical switch bindings from port binding entries.
97 * Since the binding module has already guaranteed that each vtep
98 * logical switch is bound only to one ovn-sb logical datapath,
99 * we can just iterate and assign tunnel key to vtep logical switch. */
100 SHASH_FOR_EACH (node, vtep_pbs) {
101 const struct sbrec_port_binding *port_binding_rec = node->data;
102 const char *pswitch_name = smap_get(&port_binding_rec->options,
103 "vtep-physical-switch");
104 const char *lswitch_name = smap_get(&port_binding_rec->options,
105 "vtep-logical-switch");
106 const struct vteprec_logical_switch *vtep_ls;
108 /* If 'port_binding_rec->chassis' exists then 'pswitch_name'
109 * and 'lswitch_name' must also exist. */
110 if (!pswitch_name || !lswitch_name) {
111 /* This could only happen when someone directly modifies the
112 * database. (e.g. using ovn-sbctl) */
113 VLOG_ERR("logical port (%s) with no 'options:vtep-physical-"
114 "switch' or 'options:vtep-logical-switch' specified "
115 "is bound to chassis (%s).",
116 port_binding_rec->logical_port,
117 port_binding_rec->chassis->name);
120 vtep_ls = shash_find_data(vtep_lswitches, lswitch_name);
121 /* Also checks 'pswitch_name' since the same 'lswitch_name' could
122 * exist in multiple vtep database instances and be bound to different
123 * ovn logical networks. */
124 if (vtep_ls && sset_find(vtep_pswitches, pswitch_name)) {
127 if (sset_find(&used_ls, lswitch_name)) {
131 tnl_key = port_binding_rec->datapath->tunnel_key;
132 if (vtep_ls->n_tunnel_key
133 && vtep_ls->tunnel_key[0] != tnl_key) {
134 VLOG_DBG("set vtep logical switch (%s) tunnel key from "
135 "(%"PRId64") to (%"PRId64")", vtep_ls->name,
136 vtep_ls->tunnel_key[0], tnl_key);
138 vteprec_logical_switch_set_tunnel_key(vtep_ls, &tnl_key, 1);
139 sset_add(&used_ls, lswitch_name);
142 /* Resets the tunnel keys for unused vtep logical switches. */
143 SHASH_FOR_EACH (node, vtep_lswitches) {
144 if (!sset_find(&used_ls, node->name)) {
146 vteprec_logical_switch_set_tunnel_key(node->data, &tnl_key, 1);
149 sset_destroy(&used_ls);
152 /* Updates the vtep 'Ucast_Macs_Remote' table based on non-vtep port
155 vtep_macs_run(struct ovsdb_idl_txn *vtep_idl_txn, struct shash *ucast_macs_rmts,
156 struct shash *physical_locators, struct shash *vtep_lswitches,
157 struct shash *non_vtep_pbs)
159 struct shash_node *node;
162 /* Maps from ovn logical datapath tunnel key (which is also the vtep
163 * logical switch tunnel key) to the corresponding vtep logical switch
164 * instance. Also, the shash map 'added_macs' is used for checking
165 * duplicated MAC addresses in the same ovn logical datapath. */
166 struct ls_hash_node {
167 struct hmap_node hmap_node;
169 const struct vteprec_logical_switch *vtep_ls;
170 struct shash added_macs;
174 SHASH_FOR_EACH (node, vtep_lswitches) {
175 const struct vteprec_logical_switch *vtep_ls = node->data;
176 struct ls_hash_node *ls_node;
178 if (!vtep_ls->n_tunnel_key) {
181 ls_node = xmalloc(sizeof *ls_node);
182 ls_node->vtep_ls = vtep_ls;
183 shash_init(&ls_node->added_macs);
184 hmap_insert(&ls_map, &ls_node->hmap_node,
185 hash_uint64((uint64_t) vtep_ls->tunnel_key[0]));
188 SHASH_FOR_EACH (node, non_vtep_pbs) {
189 const struct sbrec_port_binding *port_binding_rec = node->data;
190 const struct sbrec_chassis *chassis_rec;
191 struct ls_hash_node *ls_node;
192 const char *chassis_ip;
196 chassis_rec = port_binding_rec->chassis;
201 tnl_key = port_binding_rec->datapath->tunnel_key;
202 HMAP_FOR_EACH_WITH_HASH (ls_node, hmap_node,
203 hash_uint64((uint64_t) tnl_key),
205 if (ls_node->vtep_ls->tunnel_key[0] == tnl_key) {
209 /* If 'ls_node' is NULL, that means no vtep logical switch is
210 * attached to the corresponding ovn logical datapath, so pass.
216 chassis_ip = get_chassis_vtep_ip(chassis_rec);
217 /* Unreachable chassis, continue. */
219 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
220 VLOG_INFO_RL(&rl, "VTEP tunnel encap on chassis (%s) not found",
225 for (i = 0; i < port_binding_rec->n_mac; i++) {
226 const struct vteprec_ucast_macs_remote *umr;
227 const struct vteprec_physical_locator *pl;
228 const struct sbrec_port_binding *conflict;
229 char *mac = port_binding_rec->mac[i];
231 /* xxx Need to address this later when we support
232 * update of 'Mcast_Macs_Remote' table in VTEP. */
233 if (!strcmp(mac, "unknown")) {
237 /* Checks for duplicate MAC in the same vtep logical switch. */
238 conflict = shash_find_data(&ls_node->added_macs, mac);
240 VLOG_WARN("MAC address (%s) has already been known to be "
241 "on logical port (%s) in the same logical "
242 "datapath, so just ignore this logical port (%s)",
243 mac, conflict->logical_port,
244 port_binding_rec->logical_port);
247 shash_add(&ls_node->added_macs, mac, port_binding_rec);
249 char *mac_ip_tnlkey = xasprintf("%s_%s_%"PRId64, mac, chassis_ip,
251 umr = shash_find_data(ucast_macs_rmts, mac_ip_tnlkey);
252 /* If finds the 'umr' entry for the mac, ip, and tnl_key, deletes
253 * the entry from shash so that it is not gargage collected.
255 * If not found, creates a new 'umr' entry. */
256 if (umr && umr->logical_switch == ls_node->vtep_ls) {
257 shash_find_and_delete(ucast_macs_rmts, mac_ip_tnlkey);
259 const struct vteprec_ucast_macs_remote *new_umr;
261 new_umr = create_umr(vtep_idl_txn, mac, ls_node->vtep_ls);
262 pl = shash_find_data(physical_locators, chassis_ip);
264 vteprec_ucast_macs_remote_set_locator(new_umr, pl);
266 const struct vteprec_physical_locator *new_pl;
268 new_pl = create_pl(vtep_idl_txn, chassis_ip);
269 vteprec_ucast_macs_remote_set_locator(new_umr, new_pl);
270 /* Updates the 'physical_locators'. */
271 shash_add(physical_locators, chassis_ip, new_pl);
278 /* Removes all remaining 'umr's, since they do not exist anymore. */
279 SHASH_FOR_EACH (node, ucast_macs_rmts) {
280 vteprec_ucast_macs_remote_delete(node->data);
282 struct ls_hash_node *iter, *next;
283 HMAP_FOR_EACH_SAFE (iter, next, hmap_node, &ls_map) {
284 hmap_remove(&ls_map, &iter->hmap_node);
285 shash_destroy(&iter->added_macs);
288 hmap_destroy(&ls_map);
291 /* Resets all logical switches' 'tunnel_key' to NULL */
293 vtep_lswitch_cleanup(struct ovsdb_idl *vtep_idl)
295 const struct vteprec_logical_switch *vtep_ls;
298 VTEPREC_LOGICAL_SWITCH_FOR_EACH (vtep_ls, vtep_idl) {
299 if (vtep_ls->n_tunnel_key) {
300 vteprec_logical_switch_set_tunnel_key(vtep_ls, NULL, 0);
308 /* Removes all entries in the 'Ucast_Macs_Remote' table in vtep database.
309 * Returns true when all done (no entry to remove). */
311 vtep_macs_cleanup(struct ovsdb_idl *vtep_idl)
313 const struct vteprec_ucast_macs_remote *umr;
315 VTEPREC_UCAST_MACS_REMOTE_FOR_EACH (umr, vtep_idl) {
316 vteprec_ucast_macs_remote_delete(umr);
322 /* Updates vtep logical switch tunnel keys. */
324 vtep_run(struct controller_vtep_ctx *ctx)
326 if (!ctx->vtep_idl_txn) {
330 struct sset vtep_pswitches = SSET_INITIALIZER(&vtep_pswitches);
331 struct shash vtep_lswitches = SHASH_INITIALIZER(&vtep_lswitches);
332 struct shash ucast_macs_rmts = SHASH_INITIALIZER(&ucast_macs_rmts);
333 struct shash physical_locators = SHASH_INITIALIZER(&physical_locators);
334 struct shash vtep_pbs = SHASH_INITIALIZER(&vtep_pbs);
335 struct shash non_vtep_pbs = SHASH_INITIALIZER(&non_vtep_pbs);
336 const struct vteprec_physical_switch *vtep_ps;
337 const struct vteprec_logical_switch *vtep_ls;
338 const struct vteprec_ucast_macs_remote *umr;
339 const struct vteprec_physical_locator *pl;
340 const struct sbrec_port_binding *port_binding_rec;
342 /* Collects 'Physical_Switch's. */
343 VTEPREC_PHYSICAL_SWITCH_FOR_EACH (vtep_ps, ctx->vtep_idl) {
344 sset_add(&vtep_pswitches, vtep_ps->name);
347 /* Collects 'Logical_Switch's. */
348 VTEPREC_LOGICAL_SWITCH_FOR_EACH (vtep_ls, ctx->vtep_idl) {
349 shash_add(&vtep_lswitches, vtep_ls->name, vtep_ls);
352 /* Collects 'Ucast_Macs_Remote's. */
353 VTEPREC_UCAST_MACS_REMOTE_FOR_EACH (umr, ctx->vtep_idl) {
354 char *mac_ip_tnlkey =
355 xasprintf("%s_%s_%"PRId64, umr->MAC,
356 umr->locator ? umr->locator->dst_ip : "",
357 umr->logical_switch && umr->logical_switch->n_tunnel_key
358 ? umr->logical_switch->tunnel_key[0] : INT64_MAX);
360 shash_add(&ucast_macs_rmts, mac_ip_tnlkey, umr);
363 /* Collects 'Physical_Locator's. */
364 VTEPREC_PHYSICAL_LOCATOR_FOR_EACH (pl, ctx->vtep_idl) {
365 shash_add(&physical_locators, pl->dst_ip, pl);
367 /* Collects and classifies 'Port_Binding's. */
368 SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
369 struct shash *target =
370 !strcmp(port_binding_rec->type, "vtep") ? &vtep_pbs : &non_vtep_pbs;
372 if (!port_binding_rec->chassis) {
375 shash_add(target, port_binding_rec->logical_port, port_binding_rec);
378 ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn,
379 "ovn-controller-vtep: update logical switch "
380 "tunnel keys and 'ucast_macs_remote's");
382 vtep_lswitch_run(&vtep_pbs, &vtep_pswitches, &vtep_lswitches);
383 vtep_macs_run(ctx->vtep_idl_txn, &ucast_macs_rmts, &physical_locators,
384 &vtep_lswitches, &non_vtep_pbs);
386 sset_destroy(&vtep_pswitches);
387 shash_destroy(&vtep_lswitches);
388 shash_destroy(&ucast_macs_rmts);
389 shash_destroy(&physical_locators);
390 shash_destroy(&vtep_pbs);
391 shash_destroy(&non_vtep_pbs);
394 /* Cleans up all related entries in vtep. Returns true when done (i.e.
395 * there is no change made to 'ctx->vtep_idl'), otherwise returns false. */
397 vtep_cleanup(struct controller_vtep_ctx *ctx)
399 if (!ctx->vtep_idl_txn) {
405 ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn,
406 "ovn-controller-vtep: cleaning up vtep "
408 all_done = vtep_lswitch_cleanup(ctx->vtep_idl);
409 all_done = vtep_macs_cleanup(ctx->vtep_idl) && all_done;