ovn: Rename Binding table to Port_Binding.
[cascardo/ovs.git] / ovn / northd / ovn-northd.c
1 /*
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at:
5  *
6  *     http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14
15 #include <config.h>
16
17 #include <getopt.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20
21 #include "command-line.h"
22 #include "daemon.h"
23 #include "dirs.h"
24 #include "dynamic-string.h"
25 #include "fatal-signal.h"
26 #include "hash.h"
27 #include "hmap.h"
28 #include "json.h"
29 #include "ovn/lib/lex.h"
30 #include "ovn/lib/ovn-nb-idl.h"
31 #include "ovn/lib/ovn-sb-idl.h"
32 #include "poll-loop.h"
33 #include "stream.h"
34 #include "stream-ssl.h"
35 #include "unixctl.h"
36 #include "util.h"
37 #include "uuid.h"
38 #include "openvswitch/vlog.h"
39
40 VLOG_DEFINE_THIS_MODULE(ovn_northd);
41
42 static unixctl_cb_func ovn_northd_exit;
43
44 struct northd_context {
45     struct ovsdb_idl *ovnnb_idl;
46     struct ovsdb_idl *ovnsb_idl;
47     struct ovsdb_idl_txn *ovnnb_txn;
48     struct ovsdb_idl_txn *ovnsb_txn;
49 };
50
51 static const char *ovnnb_db;
52 static const char *ovnsb_db;
53
54 static const char *default_db(void);
55
56 static void
57 usage(void)
58 {
59     printf("\
60 %s: OVN northbound management daemon\n\
61 usage: %s [OPTIONS]\n\
62 \n\
63 Options:\n\
64   --ovnnb-db=DATABASE       connect to ovn-nb database at DATABASE\n\
65                             (default: %s)\n\
66   --ovnsb-db=DATABASE       connect to ovn-sb database at DATABASE\n\
67                             (default: %s)\n\
68   -h, --help                display this help message\n\
69   -o, --options             list available options\n\
70   -V, --version             display version information\n\
71 ", program_name, program_name, default_db(), default_db());
72     daemon_usage();
73     vlog_usage();
74     stream_usage("database", true, true, false);
75 }
76 \f
77 static int
78 compare_strings(const void *a_, const void *b_)
79 {
80     char *const *a = a_;
81     char *const *b = b_;
82     return strcmp(*a, *b);
83 }
84
85 /*
86  * Determine whether 2 arrays of MAC addresses are the same.  It's possible that
87  * the lists could be *very* long and this check is being done a lot (every
88  * time the OVN_Northbound database changes).
89  */
90 static bool
91 macs_equal(char **binding_macs_, size_t b_n_macs,
92            char **lport_macs_, size_t l_n_macs)
93 {
94     char **binding_macs, **lport_macs;
95     size_t bytes, i;
96
97     if (b_n_macs != l_n_macs) {
98         return false;
99     }
100
101     bytes = b_n_macs * sizeof binding_macs_[0];
102     binding_macs = xmalloc(bytes);
103     lport_macs = xmalloc(bytes);
104
105     memcpy(binding_macs, binding_macs_, bytes);
106     memcpy(lport_macs, lport_macs_, bytes);
107
108     qsort(binding_macs, b_n_macs, sizeof binding_macs[0], compare_strings);
109     qsort(lport_macs, l_n_macs, sizeof lport_macs[0], compare_strings);
110
111     for (i = 0; i < b_n_macs; i++) {
112         if (strcmp(binding_macs[i], lport_macs[i])) {
113             break;
114         }
115     }
116
117     free(binding_macs);
118     free(lport_macs);
119
120     return (i == b_n_macs) ? true : false;
121 }
122 \f
123 /* Pipeline generation.
124  *
125  * This code generates the Pipeline table in the southbound database, as a
126  * function of most of the northbound database.
127  */
128
129 /* Enough context to add a Pipeline row, using pipeline_add(). */
130 struct pipeline_ctx {
131     /* From northd_context. */
132     struct ovsdb_idl *ovnsb_idl;
133     struct ovsdb_idl_txn *ovnsb_txn;
134
135     /* Contains "struct pipeline_hash_node"s.  Used to figure out what existing
136      * Pipeline rows should be deleted: we index all of the Pipeline rows into
137      * this data structure, then as existing rows are generated we remove them.
138      * After generating all the rows, any remaining in 'pipeline_hmap' must be
139      * deleted from the database. */
140     struct hmap pipeline_hmap;
141 };
142
143 /* A row in the Pipeline table, indexed by its full contents, */
144 struct pipeline_hash_node {
145     struct hmap_node node;
146     const struct sbrec_pipeline *pipeline;
147 };
148
149 static size_t
150 pipeline_hash(const struct uuid *logical_datapath, uint8_t table_id,
151               uint16_t priority, const char *match, const char *actions)
152 {
153     size_t hash = uuid_hash(logical_datapath);
154     hash = hash_2words((table_id << 16) | priority, hash);
155     hash = hash_string(match, hash);
156     return hash_string(actions, hash);
157 }
158
159 static size_t
160 pipeline_hash_rec(const struct sbrec_pipeline *pipeline)
161 {
162     return pipeline_hash(&pipeline->logical_datapath, pipeline->table_id,
163                          pipeline->priority, pipeline->match,
164                          pipeline->actions);
165 }
166
167 /* Adds a row with the specified contents to the Pipeline table. */
168 static void
169 pipeline_add(struct pipeline_ctx *ctx,
170              const struct nbrec_logical_switch *logical_datapath,
171              uint8_t table_id,
172              uint16_t priority,
173              const char *match,
174              const char *actions)
175 {
176     struct pipeline_hash_node *hash_node;
177
178     /* Check whether such a row already exists in the Pipeline table.  If so,
179      * remove it from 'ctx->pipeline_hmap' and we're done. */
180     HMAP_FOR_EACH_WITH_HASH (hash_node, node,
181                              pipeline_hash(&logical_datapath->header_.uuid,
182                                            table_id, priority, match, actions),
183                              &ctx->pipeline_hmap) {
184         const struct sbrec_pipeline *pipeline = hash_node->pipeline;
185         if (uuid_equals(&pipeline->logical_datapath,
186                         &logical_datapath->header_.uuid)
187             && pipeline->table_id == table_id
188             && pipeline->priority == priority
189             && !strcmp(pipeline->match, match)
190             && !strcmp(pipeline->actions, actions)) {
191             hmap_remove(&ctx->pipeline_hmap, &hash_node->node);
192             free(hash_node);
193             return;
194         }
195     }
196
197     /* No such Pipeline row.  Add one. */
198     const struct sbrec_pipeline *pipeline;
199     pipeline = sbrec_pipeline_insert(ctx->ovnsb_txn);
200     sbrec_pipeline_set_logical_datapath(pipeline,
201                                         logical_datapath->header_.uuid);
202     sbrec_pipeline_set_table_id(pipeline, table_id);
203     sbrec_pipeline_set_priority(pipeline, priority);
204     sbrec_pipeline_set_match(pipeline, match);
205     sbrec_pipeline_set_actions(pipeline, actions);
206 }
207
208 /* Appends port security constraints on L2 address field 'eth_addr_field'
209  * (e.g. "eth.src" or "eth.dst") to 'match'.  'port_security', with
210  * 'n_port_security' elements, is the collection of port_security constraints
211  * from an OVN_NB Logical_Port row. */
212 static void
213 build_port_security(const char *eth_addr_field,
214                     char **port_security, size_t n_port_security,
215                     struct ds *match)
216 {
217     size_t base_len = match->length;
218     ds_put_format(match, " && %s == {", eth_addr_field);
219
220     size_t n = 0;
221     for (size_t i = 0; i < n_port_security; i++) {
222         uint8_t ea[ETH_ADDR_LEN];
223
224         if (eth_addr_from_string(port_security[i], ea)) {
225             ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
226             ds_put_char(match, ' ');
227             n++;
228         }
229     }
230     ds_chomp(match, ' ');
231     ds_put_cstr(match, "}");
232
233     if (!n) {
234         match->length = base_len;
235     }
236 }
237
238 static bool
239 lport_is_enabled(const struct nbrec_logical_port *lport)
240 {
241     return !lport->enabled || *lport->enabled;
242 }
243
244 /* Updates the Pipeline table in the OVN_SB database, constructing its contents
245  * based on the OVN_NB database. */
246 static void
247 build_pipeline(struct northd_context *ctx)
248 {
249     struct pipeline_ctx pc = {
250         .ovnsb_idl = ctx->ovnsb_idl,
251         .ovnsb_txn = ctx->ovnsb_txn,
252         .pipeline_hmap = HMAP_INITIALIZER(&pc.pipeline_hmap)
253     };
254
255     /* Add all the Pipeline entries currently in the southbound database to
256      * 'pc.pipeline_hmap'.  We remove entries that we generate from the hmap,
257      * thus by the time we're done only entries that need to be removed
258      * remain. */
259     const struct sbrec_pipeline *pipeline;
260     SBREC_PIPELINE_FOR_EACH (pipeline, ctx->ovnsb_idl) {
261         struct pipeline_hash_node *hash_node = xzalloc(sizeof *hash_node);
262         hash_node->pipeline = pipeline;
263         hmap_insert(&pc.pipeline_hmap, &hash_node->node,
264                     pipeline_hash_rec(pipeline));
265     }
266
267     /* Table 0: Admission control framework. */
268     const struct nbrec_logical_switch *lswitch;
269     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->ovnnb_idl) {
270         /* Logical VLANs not supported. */
271         pipeline_add(&pc, lswitch, 0, 100, "vlan.present", "drop;");
272
273         /* Broadcast/multicast source address is invalid. */
274         pipeline_add(&pc, lswitch, 0, 100, "eth.src[40]", "drop;");
275
276         /* Port security flows have priority 50 (see below) and will continue
277          * to the next table if packet source is acceptable. */
278
279         /* Otherwise drop the packet. */
280         pipeline_add(&pc, lswitch, 0, 0, "1", "drop;");
281     }
282
283     /* Table 0: Ingress port security. */
284     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->ovnnb_idl) {
285         for (size_t i = 0; i < lswitch->n_ports; i++) {
286             const struct nbrec_logical_port *lport = lswitch->ports[i];
287             struct ds match = DS_EMPTY_INITIALIZER;
288             ds_put_cstr(&match, "inport == ");
289             json_string_escape(lport->name, &match);
290             build_port_security("eth.src",
291                                 lport->port_security, lport->n_port_security,
292                                 &match);
293             pipeline_add(&pc, lswitch, 0, 50, ds_cstr(&match),
294                          lport_is_enabled(lport) ? "next;" : "drop;");
295             ds_destroy(&match);
296         }
297     }
298
299     /* Table 1: Destination lookup:
300      *
301      *   - Broadcast and multicast handling (priority 100).
302      *   - Unicast handling (priority 50).
303      *   - Unknown unicast address handling (priority 0).
304      *   */
305     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->ovnnb_idl) {
306         struct ds bcast;        /* Actions for broadcast on 'lswitch'. */
307         struct ds unknown;      /* Actions for unknown MACs on 'lswitch'. */
308
309         ds_init(&bcast);
310         ds_init(&unknown);
311         for (size_t i = 0; i < lswitch->n_ports; i++) {
312             const struct nbrec_logical_port *lport = lswitch->ports[i];
313
314             ds_put_cstr(&bcast, "outport = ");
315             json_string_escape(lport->name, &bcast);
316             ds_put_cstr(&bcast, "; next; ");
317
318             for (size_t j = 0; j < lport->n_macs; j++) {
319                 const char *s = lport->macs[j];
320                 uint8_t mac[ETH_ADDR_LEN];
321
322                 if (eth_addr_from_string(s, mac)) {
323                     struct ds match, unicast;
324
325                     ds_init(&match);
326                     ds_put_format(&match, "eth.dst == %s", s);
327
328                     ds_init(&unicast);
329                     ds_put_cstr(&unicast, "outport = ");
330                     json_string_escape(lport->name, &unicast);
331                     ds_put_cstr(&unicast, "; next;");
332                     pipeline_add(&pc, lswitch, 1, 50,
333                                  ds_cstr(&match), ds_cstr(&unicast));
334                     ds_destroy(&unicast);
335                     ds_destroy(&match);
336                 } else if (!strcmp(s, "unknown")) {
337                     ds_put_cstr(&unknown, "outport = ");
338                     json_string_escape(lport->name, &unknown);
339                     ds_put_cstr(&unknown, "; next; ");
340                 } else {
341                     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
342
343                     VLOG_INFO_RL(&rl, "%s: invalid syntax '%s' in macs column",
344                                  lport->name, s);
345                 }
346             }
347         }
348
349         ds_chomp(&bcast, ' ');
350         pipeline_add(&pc, lswitch, 1, 100, "eth.dst[40]", ds_cstr(&bcast));
351         ds_destroy(&bcast);
352
353         if (unknown.length) {
354             ds_chomp(&unknown, ' ');
355             pipeline_add(&pc, lswitch, 1, 0, "1", ds_cstr(&unknown));
356         }
357         ds_destroy(&unknown);
358     }
359
360     /* Table 2: ACLs. */
361     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->ovnnb_idl) {
362         for (size_t i = 0; i < lswitch->n_acls; i++) {
363             const struct nbrec_acl *acl = lswitch->acls[i];
364
365             NBREC_ACL_FOR_EACH (acl, ctx->ovnnb_idl) {
366                 pipeline_add(&pc, lswitch, 2, acl->priority, acl->match,
367                              (!strcmp(acl->action, "allow") ||
368                               !strcmp(acl->action, "allow-related")
369                               ? "next;" : "drop;"));
370             }
371         }
372
373         pipeline_add(&pc, lswitch, 2, 0, "1", "next;");
374     }
375
376     /* Table 3: Egress port security. */
377     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->ovnnb_idl) {
378         pipeline_add(&pc, lswitch, 3, 100, "eth.dst[40]", "output;");
379
380         for (size_t i = 0; i < lswitch->n_ports; i++) {
381             const struct nbrec_logical_port *lport = lswitch->ports[i];
382             struct ds match;
383
384             ds_init(&match);
385             ds_put_cstr(&match, "outport == ");
386             json_string_escape(lport->name, &match);
387             build_port_security("eth.dst",
388                                 lport->port_security, lport->n_port_security,
389                                 &match);
390
391             pipeline_add(&pc, lswitch, 3, 50, ds_cstr(&match),
392                          lport_is_enabled(lport) ? "output;" : "drop;");
393
394             ds_destroy(&match);
395         }
396     }
397
398     /* Delete any existing Pipeline rows that were not re-generated.  */
399     struct pipeline_hash_node *hash_node, *next_hash_node;
400     HMAP_FOR_EACH_SAFE (hash_node, next_hash_node, node, &pc.pipeline_hmap) {
401         hmap_remove(&pc.pipeline_hmap, &hash_node->node);
402         sbrec_pipeline_delete(hash_node->pipeline);
403         free(hash_node);
404     }
405     hmap_destroy(&pc.pipeline_hmap);
406 }
407 \f
408 /*
409  * Take two string columns and return true if:
410  *  - neither are set
411  *  - both are set and the strings are equal
412  */
413 static bool
414 strings_equal(const char *s1, const char *s2)
415 {
416     if (!!s1 != !!s2) {
417         /* One is set and the other is not. */
418         return false;
419     }
420
421     if (s1) {
422         /* Both are set. */
423         return strcmp(s1, s2) ? false : true;
424     }
425
426     /* Both are NULL. */
427     return true;
428 }
429
430 /*
431  * Take two int64_t columns and return true if either:
432  *  - neither are set
433  *  - both are set and the first integers in each are equal
434  */
435 static bool
436 int64_first_equal(int64_t *i1, size_t n_i1, int64_t *i2, size_t n_i2)
437 {
438     if (n_i1 != n_i2) {
439         return false;
440     }
441
442     return i1 ? (i1[0] == i2[0]) : true;
443 }
444
445 struct port_binding_hash_node {
446     struct hmap_node lp_node; /* In 'lp_map', by binding->logical_port. */
447     struct hmap_node tk_node; /* In 'tk_map', by binding->tunnel_key. */
448     const struct sbrec_port_binding *binding;
449 };
450
451 static bool
452 tunnel_key_in_use(const struct hmap *tk_hmap, uint16_t tunnel_key)
453 {
454     const struct port_binding_hash_node *hash_node;
455
456     HMAP_FOR_EACH_IN_BUCKET (hash_node, tk_node, hash_int(tunnel_key, 0),
457                              tk_hmap) {
458         if (hash_node->binding->tunnel_key == tunnel_key) {
459             return true;
460         }
461     }
462     return false;
463 }
464
465 /* Chooses and returns a positive tunnel key that is not already in use in
466  * 'tk_hmap'.  Returns 0 if all tunnel keys are in use. */
467 static uint16_t
468 choose_tunnel_key(const struct hmap *tk_hmap)
469 {
470     static uint16_t prev;
471
472     for (uint16_t key = prev + 1; key != prev; key++) {
473         if (!tunnel_key_in_use(tk_hmap, key)) {
474             prev = key;
475             return key;
476         }
477     }
478
479     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
480     VLOG_WARN_RL(&rl, "all tunnel keys exhausted");
481     return 0;
482 }
483
484 /*
485  * When a change has occurred in the OVN_Northbound database, we go through and
486  * make sure that the contents of the Port_Binding table in the OVN_Southbound
487  * database are up to date with the logical ports defined in the
488  * OVN_Northbound database.
489  */
490 static void
491 set_port_bindings(struct northd_context *ctx)
492 {
493     const struct sbrec_port_binding *binding;
494
495     /*
496      * We will need to look up a port binding for every logical port.  We don't
497      * want to have to do an O(n) search for every binding, so start out by
498      * hashing them on the logical port.
499      *
500      * As we go through every logical port, we will update the binding if it
501      * exists or create one otherwise.  When the update is done, we'll remove
502      * it from the hashmap.  At the end, any bindings left in the hashmap are
503      * for logical ports that have been deleted.
504      *
505      * We index the logical_port column because that's the shared key between
506      * the OVN_NB and OVN_SB databases.  We index the tunnel_key column to
507      * allow us to choose a unique tunnel key for any Port_Binding rows we have
508      * to add.
509      */
510     struct hmap lp_hmap = HMAP_INITIALIZER(&lp_hmap);
511     struct hmap tk_hmap = HMAP_INITIALIZER(&tk_hmap);
512
513     SBREC_PORT_BINDING_FOR_EACH(binding, ctx->ovnsb_idl) {
514         struct port_binding_hash_node *hash_node = xzalloc(sizeof *hash_node);
515         hash_node->binding = binding;
516         hmap_insert(&lp_hmap, &hash_node->lp_node,
517                     hash_string(binding->logical_port, 0));
518         hmap_insert(&tk_hmap, &hash_node->tk_node,
519                     hash_int(binding->tunnel_key, 0));
520     }
521
522     const struct nbrec_logical_switch *lswitch;
523     NBREC_LOGICAL_SWITCH_FOR_EACH (lswitch, ctx->ovnnb_idl) {
524         const struct uuid *logical_datapath = &lswitch->header_.uuid;
525
526         for (size_t i = 0; i < lswitch->n_ports; i++) {
527             const struct nbrec_logical_port *lport = lswitch->ports[i];
528             struct port_binding_hash_node *hash_node;
529             binding = NULL;
530             HMAP_FOR_EACH_WITH_HASH(hash_node, lp_node,
531                                     hash_string(lport->name, 0), &lp_hmap) {
532                 if (!strcmp(lport->name, hash_node->binding->logical_port)) {
533                     binding = hash_node->binding;
534                     break;
535                 }
536             }
537
538             if (binding) {
539                 /* We found an existing binding for this logical port.  Update
540                  * its contents. */
541
542                 hmap_remove(&lp_hmap, &hash_node->lp_node);
543
544                 if (!macs_equal(binding->mac, binding->n_mac,
545                                 lport->macs, lport->n_macs)) {
546                     sbrec_port_binding_set_mac(binding,
547                                                (const char **) lport->macs,
548                                                lport->n_macs);
549                 }
550                 if (!strings_equal(binding->parent_port, lport->parent_name)) {
551                     sbrec_port_binding_set_parent_port(binding,
552                                                        lport->parent_name);
553                 }
554                 if (!int64_first_equal(binding->tag, binding->n_tag,
555                                        lport->tag, lport->n_tag)) {
556                     sbrec_port_binding_set_tag(binding,
557                                                lport->tag, lport->n_tag);
558                 }
559                 if (!uuid_equals(&binding->logical_datapath,
560                                  logical_datapath)) {
561                     sbrec_port_binding_set_logical_datapath(binding,
562                                                             *logical_datapath);
563                 }
564                 if (!strings_equal(binding->type, lport->type)) {
565                     sbrec_port_binding_set_type(binding, lport->type);
566                 }
567                 if (!smap_equal(&binding->options, &lport->options)) {
568                     sbrec_port_binding_set_options(binding, &lport->options);
569                 }
570             } else {
571                 /* There is no binding for this logical port, so create one. */
572
573                 uint16_t tunnel_key = choose_tunnel_key(&tk_hmap);
574                 if (!tunnel_key) {
575                     continue;
576                 }
577
578                 binding = sbrec_port_binding_insert(ctx->ovnsb_txn);
579                 sbrec_port_binding_set_logical_port(binding, lport->name);
580                 sbrec_port_binding_set_mac(binding,
581                                            (const char **) lport->macs,
582                                            lport->n_macs);
583                 if (lport->parent_name && lport->n_tag > 0) {
584                     sbrec_port_binding_set_parent_port(binding,
585                                                        lport->parent_name);
586                     sbrec_port_binding_set_tag(binding,
587                                                lport->tag, lport->n_tag);
588                 }
589
590                 sbrec_port_binding_set_tunnel_key(binding, tunnel_key);
591                 sbrec_port_binding_set_logical_datapath(binding,
592                                                         *logical_datapath);
593
594                 sbrec_port_binding_set_type(binding, lport->type);
595                 sbrec_port_binding_set_options(binding, &lport->options);
596
597                 /* Add the tunnel key to the tk_hmap so that we don't try to
598                  * use it for another port.  (We don't want it in the lp_hmap
599                  * because that would just get the Binding record deleted
600                  * later.) */
601                 struct port_binding_hash_node *hash_node
602                     = xzalloc(sizeof *hash_node);
603                 hash_node->binding = binding;
604                 hmap_insert(&tk_hmap, &hash_node->tk_node,
605                             hash_int(binding->tunnel_key, 0));
606             }
607         }
608     }
609
610     struct port_binding_hash_node *hash_node;
611     HMAP_FOR_EACH (hash_node, lp_node, &lp_hmap) {
612         hmap_remove(&lp_hmap, &hash_node->lp_node);
613         sbrec_port_binding_delete(hash_node->binding);
614     }
615     hmap_destroy(&lp_hmap);
616
617     struct port_binding_hash_node *hash_node_next;
618     HMAP_FOR_EACH_SAFE (hash_node, hash_node_next, tk_node, &tk_hmap) {
619         hmap_remove(&tk_hmap, &hash_node->tk_node);
620         free(hash_node);
621     }
622     hmap_destroy(&tk_hmap);
623 }
624
625 static void
626 ovnnb_db_changed(struct northd_context *ctx)
627 {
628     VLOG_DBG("ovn-nb db contents have changed.");
629
630     set_port_bindings(ctx);
631     build_pipeline(ctx);
632 }
633
634 /*
635  * The only change we get notified about is if the 'chassis' column of the
636  * 'Port_Binding' table changes.  When this column is not empty, it means we
637  * need to set the corresponding logical port as 'up' in the northbound DB.
638  */
639 static void
640 ovnsb_db_changed(struct northd_context *ctx)
641 {
642     struct hmap lports_hmap;
643     const struct sbrec_port_binding *binding;
644     const struct nbrec_logical_port *lport;
645
646     struct lport_hash_node {
647         struct hmap_node node;
648         const struct nbrec_logical_port *lport;
649     } *hash_node, *hash_node_next;
650
651     VLOG_DBG("Recalculating port up states for ovn-nb db.");
652
653     hmap_init(&lports_hmap);
654
655     NBREC_LOGICAL_PORT_FOR_EACH(lport, ctx->ovnnb_idl) {
656         hash_node = xzalloc(sizeof *hash_node);
657         hash_node->lport = lport;
658         hmap_insert(&lports_hmap, &hash_node->node,
659                 hash_string(lport->name, 0));
660     }
661
662     SBREC_PORT_BINDING_FOR_EACH(binding, ctx->ovnsb_idl) {
663         lport = NULL;
664         HMAP_FOR_EACH_WITH_HASH(hash_node, node,
665                 hash_string(binding->logical_port, 0), &lports_hmap) {
666             if (!strcmp(binding->logical_port, hash_node->lport->name)) {
667                 lport = hash_node->lport;
668                 break;
669             }
670         }
671
672         if (!lport) {
673             /* The logical port doesn't exist for this port binding.  This can
674              * happen under normal circumstances when ovn-northd hasn't gotten
675              * around to pruning the Port_Binding yet. */
676             continue;
677         }
678
679         if (binding->chassis && (!lport->up || !*lport->up)) {
680             bool up = true;
681             nbrec_logical_port_set_up(lport, &up, 1);
682         } else if (!binding->chassis && (!lport->up || *lport->up)) {
683             bool up = false;
684             nbrec_logical_port_set_up(lport, &up, 1);
685         }
686     }
687
688     HMAP_FOR_EACH_SAFE(hash_node, hash_node_next, node, &lports_hmap) {
689         hmap_remove(&lports_hmap, &hash_node->node);
690         free(hash_node);
691     }
692     hmap_destroy(&lports_hmap);
693 }
694 \f
695 static const char *
696 default_db(void)
697 {
698     static char *def;
699     if (!def) {
700         def = xasprintf("unix:%s/db.sock", ovs_rundir());
701     }
702     return def;
703 }
704
705 static void
706 parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
707 {
708     enum {
709         DAEMON_OPTION_ENUMS,
710         VLOG_OPTION_ENUMS,
711     };
712     static const struct option long_options[] = {
713         {"ovnsb-db", required_argument, NULL, 'd'},
714         {"ovnnb-db", required_argument, NULL, 'D'},
715         {"help", no_argument, NULL, 'h'},
716         {"options", no_argument, NULL, 'o'},
717         {"version", no_argument, NULL, 'V'},
718         DAEMON_LONG_OPTIONS,
719         VLOG_LONG_OPTIONS,
720         STREAM_SSL_LONG_OPTIONS,
721         {NULL, 0, NULL, 0},
722     };
723     char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
724
725     for (;;) {
726         int c;
727
728         c = getopt_long(argc, argv, short_options, long_options, NULL);
729         if (c == -1) {
730             break;
731         }
732
733         switch (c) {
734         DAEMON_OPTION_HANDLERS;
735         VLOG_OPTION_HANDLERS;
736         STREAM_SSL_OPTION_HANDLERS;
737
738         case 'd':
739             ovnsb_db = optarg;
740             break;
741
742         case 'D':
743             ovnnb_db = optarg;
744             break;
745
746         case 'h':
747             usage();
748             exit(EXIT_SUCCESS);
749
750         case 'o':
751             ovs_cmdl_print_options(long_options);
752             exit(EXIT_SUCCESS);
753
754         case 'V':
755             ovs_print_version(0, 0);
756             exit(EXIT_SUCCESS);
757
758         default:
759             break;
760         }
761     }
762
763     if (!ovnsb_db) {
764         ovnsb_db = default_db();
765     }
766
767     if (!ovnnb_db) {
768         ovnnb_db = default_db();
769     }
770
771     free(short_options);
772 }
773
774 int
775 main(int argc, char *argv[])
776 {
777     extern struct vlog_module VLM_reconnect;
778     struct ovsdb_idl *ovnnb_idl, *ovnsb_idl;
779     unsigned int ovnnb_seqno, ovn_seqno;
780     int res = EXIT_SUCCESS;
781     struct northd_context ctx = {
782         .ovnsb_txn = NULL,
783     };
784     bool ovnnb_changes_pending = false;
785     bool ovn_changes_pending = false;
786     struct unixctl_server *unixctl;
787     int retval;
788     bool exiting;
789
790     fatal_ignore_sigpipe();
791     set_program_name(argv[0]);
792     vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
793     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
794     parse_options(argc, argv);
795
796     daemonize_start();
797
798     retval = unixctl_server_create(NULL, &unixctl);
799     if (retval) {
800         exit(EXIT_FAILURE);
801     }
802     unixctl_command_register("exit", "", 0, 0, ovn_northd_exit, &exiting);
803
804     daemonize_complete();
805
806     nbrec_init();
807     sbrec_init();
808
809     /* We want to detect all changes to the ovn-nb db. */
810     ctx.ovnnb_idl = ovnnb_idl = ovsdb_idl_create(ovnnb_db,
811             &nbrec_idl_class, true, true);
812
813     /* There is only a small subset of changes to the ovn-sb db that ovn-northd
814      * has to care about, so we'll enable monitoring those directly. */
815     ctx.ovnsb_idl = ovnsb_idl = ovsdb_idl_create(ovnsb_db,
816             &sbrec_idl_class, false, true);
817     ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_port_binding);
818     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_logical_port);
819     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_chassis);
820     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_mac);
821     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_tag);
822     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_parent_port);
823     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_logical_datapath);
824     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_tunnel_key);
825     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_type);
826     ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_options);
827     ovsdb_idl_add_column(ovnsb_idl, &sbrec_pipeline_col_logical_datapath);
828     ovsdb_idl_omit_alert(ovnsb_idl, &sbrec_pipeline_col_logical_datapath);
829     ovsdb_idl_add_column(ovnsb_idl, &sbrec_pipeline_col_table_id);
830     ovsdb_idl_omit_alert(ovnsb_idl, &sbrec_pipeline_col_table_id);
831     ovsdb_idl_add_column(ovnsb_idl, &sbrec_pipeline_col_priority);
832     ovsdb_idl_omit_alert(ovnsb_idl, &sbrec_pipeline_col_priority);
833     ovsdb_idl_add_column(ovnsb_idl, &sbrec_pipeline_col_match);
834     ovsdb_idl_omit_alert(ovnsb_idl, &sbrec_pipeline_col_match);
835     ovsdb_idl_add_column(ovnsb_idl, &sbrec_pipeline_col_actions);
836     ovsdb_idl_omit_alert(ovnsb_idl, &sbrec_pipeline_col_actions);
837
838     /*
839      * The loop here just runs the IDL in a loop waiting for the seqno to
840      * change, which indicates that the contents of the db have changed.
841      *
842      * If the contents of the ovn-nb db change, the mappings to the ovn-sb
843      * db must be recalculated.
844      *
845      * If the contents of the ovn-sb db change, it means the 'up' state of
846      * a port may have changed, as that's the only type of change ovn-northd is
847      * watching for.
848      */
849
850     ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl);
851     ovn_seqno = ovsdb_idl_get_seqno(ovnsb_idl);
852     exiting = false;
853     while (!exiting) {
854         ovsdb_idl_run(ovnnb_idl);
855         ovsdb_idl_run(ovnsb_idl);
856         unixctl_server_run(unixctl);
857
858         if (!ovsdb_idl_is_alive(ovnnb_idl)) {
859             int retval = ovsdb_idl_get_last_error(ovnnb_idl);
860             VLOG_ERR("%s: database connection failed (%s)",
861                     ovnnb_db, ovs_retval_to_string(retval));
862             res = EXIT_FAILURE;
863             break;
864         }
865
866         if (!ovsdb_idl_is_alive(ovnsb_idl)) {
867             int retval = ovsdb_idl_get_last_error(ovnsb_idl);
868             VLOG_ERR("%s: database connection failed (%s)",
869                     ovnsb_db, ovs_retval_to_string(retval));
870             res = EXIT_FAILURE;
871             break;
872         }
873
874         if (ovnnb_seqno != ovsdb_idl_get_seqno(ovnnb_idl)) {
875             ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl);
876             ovnnb_changes_pending = true;
877         }
878
879         if (ovn_seqno != ovsdb_idl_get_seqno(ovnsb_idl)) {
880             ovn_seqno = ovsdb_idl_get_seqno(ovnsb_idl);
881             ovn_changes_pending = true;
882         }
883
884         /*
885          * If there are any pending changes, we delay recalculating the
886          * necessary updates until after an existing transaction finishes.
887          * This avoids the possibility of rapid updates causing ovn-northd to
888          * never be able to successfully make the corresponding updates to the
889          * other db.  Instead, pending changes are batched up until the next
890          * time we get a chance to calculate the new state and apply it.
891          */
892
893         if (ovnnb_changes_pending && !ctx.ovnsb_txn) {
894             /*
895              * The OVN-nb db contents have changed, so create a transaction for
896              * updating the OVN-sb DB.
897              */
898             ctx.ovnsb_txn = ovsdb_idl_txn_create(ctx.ovnsb_idl);
899             ovsdb_idl_txn_add_comment(ctx.ovnsb_txn,
900                                       "ovn-northd: northbound db changed");
901             ovnnb_db_changed(&ctx);
902             ovnnb_changes_pending = false;
903         }
904
905         if (ovn_changes_pending && !ctx.ovnnb_txn) {
906             /*
907              * The OVN-sb db contents have changed, so create a transaction for
908              * updating the northbound DB.
909              */
910             ctx.ovnnb_txn = ovsdb_idl_txn_create(ctx.ovnnb_idl);
911             ovsdb_idl_txn_add_comment(ctx.ovnnb_txn,
912                                       "ovn-northd: southbound db changed");
913             ovnsb_db_changed(&ctx);
914             ovn_changes_pending = false;
915         }
916
917         if (ctx.ovnnb_txn) {
918             enum ovsdb_idl_txn_status txn_status;
919             txn_status = ovsdb_idl_txn_commit(ctx.ovnnb_txn);
920             switch (txn_status) {
921             case TXN_UNCOMMITTED:
922             case TXN_INCOMPLETE:
923                 /* Come back around and try to commit this transaction again */
924                 break;
925             case TXN_ABORTED:
926             case TXN_TRY_AGAIN:
927             case TXN_NOT_LOCKED:
928             case TXN_ERROR:
929                 /* Something went wrong, so try creating a new transaction. */
930                 ovn_changes_pending = true;
931             case TXN_UNCHANGED:
932             case TXN_SUCCESS:
933                 ovsdb_idl_txn_destroy(ctx.ovnnb_txn);
934                 ctx.ovnnb_txn = NULL;
935             }
936         }
937
938         if (ctx.ovnsb_txn) {
939             enum ovsdb_idl_txn_status txn_status;
940             txn_status = ovsdb_idl_txn_commit(ctx.ovnsb_txn);
941             switch (txn_status) {
942             case TXN_UNCOMMITTED:
943             case TXN_INCOMPLETE:
944                 /* Come back around and try to commit this transaction again */
945                 break;
946             case TXN_ABORTED:
947             case TXN_TRY_AGAIN:
948             case TXN_NOT_LOCKED:
949             case TXN_ERROR:
950                 /* Something went wrong, so try creating a new transaction. */
951                 ovnnb_changes_pending = true;
952             case TXN_UNCHANGED:
953             case TXN_SUCCESS:
954                 ovsdb_idl_txn_destroy(ctx.ovnsb_txn);
955                 ctx.ovnsb_txn = NULL;
956             }
957         }
958
959         if (ovnnb_seqno == ovsdb_idl_get_seqno(ovnnb_idl) &&
960                 ovn_seqno == ovsdb_idl_get_seqno(ovnsb_idl)) {
961             ovsdb_idl_wait(ovnnb_idl);
962             ovsdb_idl_wait(ovnsb_idl);
963             if (ctx.ovnnb_txn) {
964                 ovsdb_idl_txn_wait(ctx.ovnnb_txn);
965             }
966             if (ctx.ovnsb_txn) {
967                 ovsdb_idl_txn_wait(ctx.ovnsb_txn);
968             }
969             unixctl_server_wait(unixctl);
970             if (exiting) {
971                 poll_immediate_wake();
972             }
973             poll_block();
974         }
975     }
976
977     unixctl_server_destroy(unixctl);
978     ovsdb_idl_destroy(ovnsb_idl);
979     ovsdb_idl_destroy(ovnnb_idl);
980
981     exit(res);
982 }
983
984 static void
985 ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
986                 const char *argv[] OVS_UNUSED, void *exiting_)
987 {
988     bool *exiting = exiting_;
989     *exiting = true;
990
991     unixctl_command_reply(conn, NULL);
992 }