flow: add miniflow_pad_from_64
[cascardo/ovs.git] / ovn / controller-vtep / vtep.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
18 #include "vtep.h"
19
20 #include "lib/hash.h"
21 #include "lib/hmap.h"
22 #include "lib/shash.h"
23 #include "lib/smap.h"
24 #include "lib/sset.h"
25 #include "lib/util.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"
30
31 VLOG_DEFINE_THIS_MODULE(vtep);
32
33 /*
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
36  * database.
37  *
38  */
39 \f
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. */
43 static const char *
44 get_chassis_vtep_ip(const struct sbrec_chassis *chassis_rec)
45 {
46     if (chassis_rec) {
47         size_t i;
48
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;
52             }
53         }
54     }
55
56     return NULL;
57 }
58
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)
63 {
64     struct vteprec_ucast_macs_remote *new_umr;
65
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);
69
70     return new_umr;
71 }
72
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)
76 {
77     struct vteprec_physical_locator *new_pl;
78
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);
82
83     return new_pl;
84 }
85
86 \f
87 /* Updates the vtep Logical_Switch table entries' tunnel keys based
88  * on the port bindings. */
89 static void
90 vtep_lswitch_run(struct shash *vtep_pbs, struct sset *vtep_pswitches,
91                  struct shash *vtep_lswitches)
92 {
93     struct sset used_ls = SSET_INITIALIZER(&used_ls);
94     struct shash_node *node;
95
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;
107
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);
118             continue;
119         }
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)) {
125             int64_t tnl_key;
126
127             if (sset_find(&used_ls, lswitch_name)) {
128                 continue;
129             }
130
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);
137             }
138             vteprec_logical_switch_set_tunnel_key(vtep_ls, &tnl_key, 1);
139             sset_add(&used_ls, lswitch_name);
140         }
141     }
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)) {
145             int64_t tnl_key = 0;
146             vteprec_logical_switch_set_tunnel_key(node->data, &tnl_key, 1);
147         }
148     }
149     sset_destroy(&used_ls);
150 }
151
152 /* Updates the vtep 'Ucast_Macs_Remote' table based on non-vtep port
153  * bindings. */
154 static void
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)
158 {
159     struct shash_node *node;
160     struct hmap ls_map;
161
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;
168
169         const struct vteprec_logical_switch *vtep_ls;
170         struct shash added_macs;
171     };
172
173     hmap_init(&ls_map);
174     SHASH_FOR_EACH (node, vtep_lswitches) {
175         const struct vteprec_logical_switch *vtep_ls = node->data;
176         struct ls_hash_node *ls_node;
177
178         if (!vtep_ls->n_tunnel_key) {
179             continue;
180         }
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]));
186     }
187
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;
193         int64_t tnl_key;
194         size_t i;
195
196         chassis_rec = port_binding_rec->chassis;
197         if (!chassis_rec) {
198             continue;
199         }
200
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),
204                                  &ls_map) {
205             if (ls_node->vtep_ls->tunnel_key[0] == tnl_key) {
206                 break;
207             }
208         }
209         /* If 'ls_node' is NULL, that means no vtep logical switch is
210          * attached to the corresponding ovn logical datapath, so pass.
211          */
212         if (!ls_node) {
213             continue;
214         }
215
216         chassis_ip = get_chassis_vtep_ip(chassis_rec);
217         /* Unreachable chassis, continue. */
218         if (!chassis_ip) {
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",
221                          chassis_rec->name);
222             continue;
223         }
224
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];
230
231             /* xxx Need to address this later when we support
232              * update of 'Mcast_Macs_Remote' table in VTEP. */
233             if (!strcmp(mac, "unknown")) {
234                 continue;
235             }
236
237             /* Checks for duplicate MAC in the same vtep logical switch. */
238             conflict = shash_find_data(&ls_node->added_macs, mac);
239             if (conflict) {
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);
245                 continue;
246             }
247             shash_add(&ls_node->added_macs, mac, port_binding_rec);
248
249             char *mac_ip_tnlkey = xasprintf("%s_%s_%"PRId64, mac, chassis_ip,
250                                             tnl_key);
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.
254              *
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);
258             } else {
259                 const struct vteprec_ucast_macs_remote *new_umr;
260
261                 new_umr = create_umr(vtep_idl_txn, mac, ls_node->vtep_ls);
262                 pl = shash_find_data(physical_locators, chassis_ip);
263                 if (pl) {
264                     vteprec_ucast_macs_remote_set_locator(new_umr, pl);
265                 } else {
266                     const struct vteprec_physical_locator *new_pl;
267
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);
272                 }
273             }
274             free(mac_ip_tnlkey);
275         }
276     }
277
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);
281     }
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);
286         free(iter);
287     }
288     hmap_destroy(&ls_map);
289 }
290
291 /* Resets all logical switches' 'tunnel_key' to NULL */
292 static bool
293 vtep_lswitch_cleanup(struct ovsdb_idl *vtep_idl)
294 {
295    const struct vteprec_logical_switch *vtep_ls;
296     bool done = true;
297
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);
301             done = false;
302         }
303     }
304
305     return done;
306 }
307
308 /* Removes all entries in the 'Ucast_Macs_Remote' table in vtep database.
309  * Returns true when all done (no entry to remove). */
310 static bool
311 vtep_macs_cleanup(struct ovsdb_idl *vtep_idl)
312 {
313     const struct vteprec_ucast_macs_remote *umr;
314
315     VTEPREC_UCAST_MACS_REMOTE_FOR_EACH (umr, vtep_idl) {
316         vteprec_ucast_macs_remote_delete(umr);
317         return false;
318     }
319     return true;
320 }
321 \f
322 /* Updates vtep logical switch tunnel keys. */
323 void
324 vtep_run(struct controller_vtep_ctx *ctx)
325 {
326     if (!ctx->vtep_idl_txn) {
327         return;
328     }
329
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;
341
342     /* Collects 'Physical_Switch's. */
343     VTEPREC_PHYSICAL_SWITCH_FOR_EACH (vtep_ps, ctx->vtep_idl) {
344         sset_add(&vtep_pswitches, vtep_ps->name);
345     }
346
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);
350     }
351
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);
359
360         shash_add(&ucast_macs_rmts, mac_ip_tnlkey, umr);
361         free(mac_ip_tnlkey);
362     }
363     /* Collects 'Physical_Locator's. */
364     VTEPREC_PHYSICAL_LOCATOR_FOR_EACH (pl, ctx->vtep_idl) {
365         shash_add(&physical_locators, pl->dst_ip, pl);
366     }
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;
371
372         if (!port_binding_rec->chassis) {
373             continue;
374         }
375         shash_add(target, port_binding_rec->logical_port, port_binding_rec);
376     }
377
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");
381
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);
385
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);
392 }
393
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. */
396 bool
397 vtep_cleanup(struct controller_vtep_ctx *ctx)
398 {
399     if (!ctx->vtep_idl_txn) {
400         return false;
401     }
402
403     bool all_done;
404
405     ovsdb_idl_txn_add_comment(ctx->vtep_idl_txn,
406                               "ovn-controller-vtep: cleaning up vtep "
407                               "configuration");
408     all_done = vtep_lswitch_cleanup(ctx->vtep_idl);
409     all_done = vtep_macs_cleanup(ctx->vtep_idl) && all_done;
410
411     return all_done;
412 }