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