]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/northd/ovn-northd.c
ovn-northd: Don't deliver even broadcast packets to disabled logical ports.
[mirror_ovs.git] / ovn / northd / ovn-northd.c
CommitLineData
ac0630a2
RB
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"
67d9b930 22#include "daemon.h"
ac0630a2 23#include "dirs.h"
bd39395f 24#include "dynamic-string.h"
ac0630a2 25#include "fatal-signal.h"
4edcdcf4
RB
26#include "hash.h"
27#include "hmap.h"
bd39395f
BP
28#include "json.h"
29#include "ovn/lib/lex.h"
e3df8838
BP
30#include "ovn/lib/ovn-nb-idl.h"
31#include "ovn/lib/ovn-sb-idl.h"
ac0630a2 32#include "poll-loop.h"
5868eb24 33#include "smap.h"
ac0630a2
RB
34#include "stream.h"
35#include "stream-ssl.h"
7b303ff9 36#include "unixctl.h"
ac0630a2 37#include "util.h"
4edcdcf4 38#include "uuid.h"
ac0630a2
RB
39#include "openvswitch/vlog.h"
40
2e2762d4 41VLOG_DEFINE_THIS_MODULE(ovn_northd);
ac0630a2 42
7b303ff9
AW
43static unixctl_cb_func ovn_northd_exit;
44
2e2762d4 45struct northd_context {
f93818dd 46 struct ovsdb_idl *ovnnb_idl;
ec78987f 47 struct ovsdb_idl *ovnsb_idl;
f93818dd 48 struct ovsdb_idl_txn *ovnnb_txn;
3c78b3ca 49 struct ovsdb_idl_txn *ovnsb_txn;
f93818dd
RB
50};
51
ac0630a2 52static const char *ovnnb_db;
ec78987f 53static const char *ovnsb_db;
ac0630a2
RB
54
55static const char *default_db(void);
56
091e3af9
JP
57
58/* Ingress pipeline stages.
59 *
60 * These must be listed in the order that the stages will be executed. */
61#define INGRESS_STAGES \
62 INGRESS_STAGE(PORT_SEC, port_sec) \
1b19bbb4 63 INGRESS_STAGE(ACL, acl) \
091e3af9
JP
64 INGRESS_STAGE(L2_LKUP, l2_lkup)
65
66enum ingress_stage {
67#define INGRESS_STAGE(NAME, STR) S_IN_##NAME,
68 INGRESS_STAGES
69#undef INGRESS_STAGE
70 INGRESS_N_STAGES
71};
72
73/* Egress pipeline stages.
74 *
75 * These must be listed in the order that the stages will be executed. */
76#define EGRESS_STAGES \
77 EGRESS_STAGE(ACL, acl) \
78 EGRESS_STAGE(PORT_SEC, port_sec)
79
80enum egress_stage {
81#define EGRESS_STAGE(NAME, STR) S_OUT_##NAME,
82 EGRESS_STAGES
83#undef EGRESS_STAGE
84 EGRESS_N_STAGES
85};
86
ac0630a2
RB
87static void
88usage(void)
89{
90 printf("\
91%s: OVN northbound management daemon\n\
92usage: %s [OPTIONS]\n\
93\n\
94Options:\n\
95 --ovnnb-db=DATABASE connect to ovn-nb database at DATABASE\n\
96 (default: %s)\n\
ec78987f 97 --ovnsb-db=DATABASE connect to ovn-sb database at DATABASE\n\
ac0630a2
RB
98 (default: %s)\n\
99 -h, --help display this help message\n\
100 -o, --options list available options\n\
101 -V, --version display version information\n\
102", program_name, program_name, default_db(), default_db());
67d9b930 103 daemon_usage();
ac0630a2
RB
104 vlog_usage();
105 stream_usage("database", true, true, false);
106}
107\f
5868eb24
BP
108struct tnlid_node {
109 struct hmap_node hmap_node;
110 uint32_t tnlid;
111};
112
113static void
114destroy_tnlids(struct hmap *tnlids)
4edcdcf4 115{
5868eb24
BP
116 struct tnlid_node *node, *next;
117 HMAP_FOR_EACH_SAFE (node, next, hmap_node, tnlids) {
118 hmap_remove(tnlids, &node->hmap_node);
119 free(node);
120 }
121 hmap_destroy(tnlids);
122}
123
124static void
125add_tnlid(struct hmap *set, uint32_t tnlid)
126{
127 struct tnlid_node *node = xmalloc(sizeof *node);
128 hmap_insert(set, &node->hmap_node, hash_int(tnlid, 0));
129 node->tnlid = tnlid;
4edcdcf4
RB
130}
131
4edcdcf4 132static bool
5868eb24 133tnlid_in_use(const struct hmap *set, uint32_t tnlid)
4edcdcf4 134{
5868eb24
BP
135 const struct tnlid_node *node;
136 HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_int(tnlid, 0), set) {
137 if (node->tnlid == tnlid) {
138 return true;
139 }
140 }
141 return false;
142}
4edcdcf4 143
5868eb24
BP
144static uint32_t
145allocate_tnlid(struct hmap *set, const char *name, uint32_t max,
146 uint32_t *hint)
147{
148 for (uint32_t tnlid = *hint + 1; tnlid != *hint;
149 tnlid = tnlid + 1 <= max ? tnlid + 1 : 1) {
150 if (!tnlid_in_use(set, tnlid)) {
151 add_tnlid(set, tnlid);
152 *hint = tnlid;
153 return tnlid;
154 }
4edcdcf4
RB
155 }
156
5868eb24
BP
157 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
158 VLOG_WARN_RL(&rl, "all %s tunnel ids exhausted", name);
159 return 0;
160}
161\f
162/* The 'key' comes from nb->header_.uuid or sb->external_ids:logical-switch. */
163struct ovn_datapath {
164 struct hmap_node key_node; /* Index on 'key'. */
165 struct uuid key; /* nb->header_.uuid. */
4edcdcf4 166
5868eb24
BP
167 const struct nbrec_logical_switch *nb; /* May be NULL. */
168 const struct sbrec_datapath_binding *sb; /* May be NULL. */
4edcdcf4 169
5868eb24 170 struct ovs_list list; /* In list of similar records. */
4edcdcf4 171
5868eb24
BP
172 struct hmap port_tnlids;
173 uint32_t port_key_hint;
174
175 bool has_unknown;
176};
177
178static struct ovn_datapath *
179ovn_datapath_create(struct hmap *datapaths, const struct uuid *key,
180 const struct nbrec_logical_switch *nb,
181 const struct sbrec_datapath_binding *sb)
182{
183 struct ovn_datapath *od = xzalloc(sizeof *od);
184 od->key = *key;
185 od->sb = sb;
186 od->nb = nb;
187 hmap_init(&od->port_tnlids);
188 od->port_key_hint = 0;
189 hmap_insert(datapaths, &od->key_node, uuid_hash(&od->key));
190 return od;
191}
192
193static void
194ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
195{
196 if (od) {
197 /* Don't remove od->list. It is used within build_datapaths() as a
198 * private list and once we've exited that function it is not safe to
199 * use it. */
200 hmap_remove(datapaths, &od->key_node);
201 destroy_tnlids(&od->port_tnlids);
202 free(od);
203 }
204}
205
206static struct ovn_datapath *
207ovn_datapath_find(struct hmap *datapaths, const struct uuid *uuid)
208{
209 struct ovn_datapath *od;
210
211 HMAP_FOR_EACH_WITH_HASH (od, key_node, uuid_hash(uuid), datapaths) {
212 if (uuid_equals(uuid, &od->key)) {
213 return od;
214 }
215 }
216 return NULL;
217}
218
219static struct ovn_datapath *
220ovn_datapath_from_sbrec(struct hmap *datapaths,
221 const struct sbrec_datapath_binding *sb)
222{
223 struct uuid key;
224
225 if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key)) {
226 return NULL;
227 }
228 return ovn_datapath_find(datapaths, &key);
229}
230
231static void
232join_datapaths(struct northd_context *ctx, struct hmap *datapaths,
233 struct ovs_list *sb_only, struct ovs_list *nb_only,
234 struct ovs_list *both)
235{
236 hmap_init(datapaths);
237 list_init(sb_only);
238 list_init(nb_only);
239 list_init(both);
240
241 const struct sbrec_datapath_binding *sb, *sb_next;
242 SBREC_DATAPATH_BINDING_FOR_EACH_SAFE (sb, sb_next, ctx->ovnsb_idl) {
243 struct uuid key;
244 if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key)) {
245 ovsdb_idl_txn_add_comment(ctx->ovnsb_txn,
246 "deleting Datapath_Binding "UUID_FMT" that "
247 "lacks external-ids:logical-switch",
248 UUID_ARGS(&sb->header_.uuid));
249 sbrec_datapath_binding_delete(sb);
250 continue;
251 }
252
253 if (ovn_datapath_find(datapaths, &key)) {
254 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
255 VLOG_INFO_RL(&rl, "deleting Datapath_Binding "UUID_FMT" with "
256 "duplicate external-ids:logical-switch "UUID_FMT,
257 UUID_ARGS(&sb->header_.uuid), UUID_ARGS(&key));
258 sbrec_datapath_binding_delete(sb);
259 continue;
260 }
261
262 struct ovn_datapath *od = ovn_datapath_create(datapaths, &key,
263 NULL, sb);
264 list_push_back(sb_only, &od->list);
265 }
266
267 const struct nbrec_logical_switch *nb;
268 NBREC_LOGICAL_SWITCH_FOR_EACH (nb, ctx->ovnnb_idl) {
269 struct ovn_datapath *od = ovn_datapath_find(datapaths,
270 &nb->header_.uuid);
271 if (od) {
272 od->nb = nb;
273 list_remove(&od->list);
274 list_push_back(both, &od->list);
275 } else {
276 od = ovn_datapath_create(datapaths, &nb->header_.uuid, nb, NULL);
277 list_push_back(nb_only, &od->list);
278 }
279 }
280}
281
282static uint32_t
283ovn_datapath_allocate_key(struct hmap *dp_tnlids)
284{
285 static uint32_t hint;
286 return allocate_tnlid(dp_tnlids, "datapath", (1u << 24) - 1, &hint);
287}
288
289static void
290build_datapaths(struct northd_context *ctx, struct hmap *datapaths)
291{
292 struct ovs_list sb_only, nb_only, both;
293
294 join_datapaths(ctx, datapaths, &sb_only, &nb_only, &both);
295
296 if (!list_is_empty(&nb_only)) {
297 /* First index the in-use datapath tunnel IDs. */
298 struct hmap dp_tnlids = HMAP_INITIALIZER(&dp_tnlids);
299 struct ovn_datapath *od;
300 LIST_FOR_EACH (od, list, &both) {
301 add_tnlid(&dp_tnlids, od->sb->tunnel_key);
302 }
303
304 /* Add southbound record for each unmatched northbound record. */
305 LIST_FOR_EACH (od, list, &nb_only) {
306 uint16_t tunnel_key = ovn_datapath_allocate_key(&dp_tnlids);
307 if (!tunnel_key) {
308 break;
309 }
310
311 od->sb = sbrec_datapath_binding_insert(ctx->ovnsb_txn);
312
5868eb24
BP
313 char uuid_s[UUID_LEN + 1];
314 sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->nb->header_.uuid));
aaf881c6
BP
315 const struct smap id = SMAP_CONST1(&id, "logical-switch", uuid_s);
316 sbrec_datapath_binding_set_external_ids(od->sb, &id);
5868eb24
BP
317
318 sbrec_datapath_binding_set_tunnel_key(od->sb, tunnel_key);
319 }
320 destroy_tnlids(&dp_tnlids);
321 }
322
323 /* Delete southbound records without northbound matches. */
324 struct ovn_datapath *od, *next;
325 LIST_FOR_EACH_SAFE (od, next, list, &sb_only) {
326 list_remove(&od->list);
327 sbrec_datapath_binding_delete(od->sb);
328 ovn_datapath_destroy(datapaths, od);
329 }
330}
331\f
332struct ovn_port {
333 struct hmap_node key_node; /* Index on 'key'. */
334 const char *key; /* nb->name and sb->logical_port */
335
336 const struct nbrec_logical_port *nb; /* May be NULL. */
337 const struct sbrec_port_binding *sb; /* May be NULL. */
338
339 struct ovn_datapath *od;
340
341 struct ovs_list list; /* In list of similar records. */
342};
343
344static struct ovn_port *
345ovn_port_create(struct hmap *ports, const char *key,
346 const struct nbrec_logical_port *nb,
347 const struct sbrec_port_binding *sb)
348{
349 struct ovn_port *op = xzalloc(sizeof *op);
350 op->key = key;
351 op->sb = sb;
352 op->nb = nb;
353 hmap_insert(ports, &op->key_node, hash_string(op->key, 0));
354 return op;
355}
356
357static void
358ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
359{
360 if (port) {
361 /* Don't remove port->list. It is used within build_ports() as a
362 * private list and once we've exited that function it is not safe to
363 * use it. */
364 hmap_remove(ports, &port->key_node);
365 free(port);
366 }
367}
368
369static struct ovn_port *
370ovn_port_find(struct hmap *ports, const char *name)
371{
372 struct ovn_port *op;
373
374 HMAP_FOR_EACH_WITH_HASH (op, key_node, hash_string(name, 0), ports) {
375 if (!strcmp(op->key, name)) {
376 return op;
377 }
378 }
379 return NULL;
380}
381
382static uint32_t
383ovn_port_allocate_key(struct ovn_datapath *od)
384{
385 return allocate_tnlid(&od->port_tnlids, "port",
386 (1u << 15) - 1, &od->port_key_hint);
387}
388
389static void
390join_logical_ports(struct northd_context *ctx,
391 struct hmap *datapaths, struct hmap *ports,
392 struct ovs_list *sb_only, struct ovs_list *nb_only,
393 struct ovs_list *both)
394{
395 hmap_init(ports);
396 list_init(sb_only);
397 list_init(nb_only);
398 list_init(both);
399
400 const struct sbrec_port_binding *sb;
401 SBREC_PORT_BINDING_FOR_EACH (sb, ctx->ovnsb_idl) {
402 struct ovn_port *op = ovn_port_create(ports, sb->logical_port,
403 NULL, sb);
404 list_push_back(sb_only, &op->list);
405 }
406
407 struct ovn_datapath *od;
408 HMAP_FOR_EACH (od, key_node, datapaths) {
409 for (size_t i = 0; i < od->nb->n_ports; i++) {
410 const struct nbrec_logical_port *nb = od->nb->ports[i];
411 struct ovn_port *op = ovn_port_find(ports, nb->name);
412 if (op) {
413 op->nb = nb;
414 list_remove(&op->list);
415 list_push_back(both, &op->list);
416 } else {
417 op = ovn_port_create(ports, nb->name, nb, NULL);
418 list_push_back(nb_only, &op->list);
419 }
420 op->od = od;
421 }
422 }
423}
424
425static void
426ovn_port_update_sbrec(const struct ovn_port *op)
427{
bf4afb5a
AW
428 sbrec_port_binding_set_type(op->sb, op->nb->type);
429 sbrec_port_binding_set_options(op->sb, &op->nb->options);
5868eb24
BP
430 sbrec_port_binding_set_datapath(op->sb, op->od->sb);
431 sbrec_port_binding_set_parent_port(op->sb, op->nb->parent_name);
432 sbrec_port_binding_set_tag(op->sb, op->nb->tag, op->nb->n_tag);
433 sbrec_port_binding_set_mac(op->sb, (const char **) op->nb->macs,
434 op->nb->n_macs);
435}
436
437static void
438build_ports(struct northd_context *ctx, struct hmap *datapaths,
439 struct hmap *ports)
440{
441 struct ovs_list sb_only, nb_only, both;
442
443 join_logical_ports(ctx, datapaths, ports, &sb_only, &nb_only, &both);
444
445 /* For logical ports that are in both databases, update the southbound
446 * record based on northbound data. Also index the in-use tunnel_keys. */
447 struct ovn_port *op, *next;
448 LIST_FOR_EACH_SAFE (op, next, list, &both) {
449 ovn_port_update_sbrec(op);
450
451 add_tnlid(&op->od->port_tnlids, op->sb->tunnel_key);
452 if (op->sb->tunnel_key > op->od->port_key_hint) {
453 op->od->port_key_hint = op->sb->tunnel_key;
454 }
455 }
456
457 /* Add southbound record for each unmatched northbound record. */
458 LIST_FOR_EACH_SAFE (op, next, list, &nb_only) {
459 uint16_t tunnel_key = ovn_port_allocate_key(op->od);
460 if (!tunnel_key) {
461 continue;
462 }
463
464 op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn);
465 ovn_port_update_sbrec(op);
466
467 sbrec_port_binding_set_logical_port(op->sb, op->key);
468 sbrec_port_binding_set_tunnel_key(op->sb, tunnel_key);
469 }
470
471 /* Delete southbound records without northbound matches. */
472 LIST_FOR_EACH_SAFE(op, next, list, &sb_only) {
473 list_remove(&op->list);
474 sbrec_port_binding_delete(op->sb);
475 ovn_port_destroy(ports, op);
476 }
477}
478\f
479#define OVN_MIN_MULTICAST 32768
480#define OVN_MAX_MULTICAST 65535
481
482struct multicast_group {
483 const char *name;
484 uint16_t key; /* OVN_MIN_MULTICAST...OVN_MAX_MULTICAST. */
485};
486
487#define MC_FLOOD "_MC_flood"
488static const struct multicast_group mc_flood = { MC_FLOOD, 65535 };
489
490#define MC_UNKNOWN "_MC_unknown"
491static const struct multicast_group mc_unknown = { MC_UNKNOWN, 65534 };
492
493static bool
494multicast_group_equal(const struct multicast_group *a,
495 const struct multicast_group *b)
496{
497 return !strcmp(a->name, b->name) && a->key == b->key;
498}
499
500/* Multicast group entry. */
501struct ovn_multicast {
502 struct hmap_node hmap_node; /* Index on 'datapath' and 'key'. */
503 struct ovn_datapath *datapath;
504 const struct multicast_group *group;
505
506 struct ovn_port **ports;
507 size_t n_ports, allocated_ports;
508};
509
510static uint32_t
511ovn_multicast_hash(const struct ovn_datapath *datapath,
512 const struct multicast_group *group)
513{
514 return hash_pointer(datapath, group->key);
515}
516
517static struct ovn_multicast *
518ovn_multicast_find(struct hmap *mcgroups, struct ovn_datapath *datapath,
519 const struct multicast_group *group)
520{
521 struct ovn_multicast *mc;
522
523 HMAP_FOR_EACH_WITH_HASH (mc, hmap_node,
524 ovn_multicast_hash(datapath, group), mcgroups) {
525 if (mc->datapath == datapath
526 && multicast_group_equal(mc->group, group)) {
527 return mc;
4edcdcf4
RB
528 }
529 }
5868eb24
BP
530 return NULL;
531}
532
533static void
534ovn_multicast_add(struct hmap *mcgroups, const struct multicast_group *group,
535 struct ovn_port *port)
536{
537 struct ovn_datapath *od = port->od;
538 struct ovn_multicast *mc = ovn_multicast_find(mcgroups, od, group);
539 if (!mc) {
540 mc = xmalloc(sizeof *mc);
541 hmap_insert(mcgroups, &mc->hmap_node, ovn_multicast_hash(od, group));
542 mc->datapath = od;
543 mc->group = group;
544 mc->n_ports = 0;
545 mc->allocated_ports = 4;
546 mc->ports = xmalloc(mc->allocated_ports * sizeof *mc->ports);
547 }
548 if (mc->n_ports >= mc->allocated_ports) {
549 mc->ports = x2nrealloc(mc->ports, &mc->allocated_ports,
550 sizeof *mc->ports);
551 }
552 mc->ports[mc->n_ports++] = port;
553}
4edcdcf4 554
5868eb24
BP
555static void
556ovn_multicast_destroy(struct hmap *mcgroups, struct ovn_multicast *mc)
557{
558 if (mc) {
559 hmap_remove(mcgroups, &mc->hmap_node);
560 free(mc->ports);
561 free(mc);
562 }
563}
4edcdcf4 564
5868eb24
BP
565static void
566ovn_multicast_update_sbrec(const struct ovn_multicast *mc,
567 const struct sbrec_multicast_group *sb)
568{
569 struct sbrec_port_binding **ports = xmalloc(mc->n_ports * sizeof *ports);
570 for (size_t i = 0; i < mc->n_ports; i++) {
571 ports[i] = CONST_CAST(struct sbrec_port_binding *, mc->ports[i]->sb);
572 }
573 sbrec_multicast_group_set_ports(sb, ports, mc->n_ports);
574 free(ports);
4edcdcf4 575}
bd39395f 576\f
48605550 577/* Logical flow generation.
bd39395f 578 *
48605550 579 * This code generates the Logical_Flow table in the southbound database, as a
bd39395f
BP
580 * function of most of the northbound database.
581 */
582
5868eb24
BP
583struct ovn_lflow {
584 struct hmap_node hmap_node;
bd39395f 585
5868eb24
BP
586 struct ovn_datapath *od;
587 enum ovn_pipeline { P_IN, P_OUT } pipeline;
588 uint8_t table_id;
589 uint16_t priority;
590 char *match;
591 char *actions;
bd39395f
BP
592};
593
594static size_t
5868eb24 595ovn_lflow_hash(const struct ovn_lflow *lflow)
bd39395f 596{
5868eb24
BP
597 size_t hash = uuid_hash(&lflow->od->key);
598 hash = hash_2words((lflow->table_id << 16) | lflow->priority, hash);
599 hash = hash_string(lflow->match, hash);
600 return hash_string(lflow->actions, hash);
bd39395f
BP
601}
602
5868eb24
BP
603static bool
604ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b)
605{
606 return (a->od == b->od
607 && a->pipeline == b->pipeline
608 && a->table_id == b->table_id
609 && a->priority == b->priority
610 && !strcmp(a->match, b->match)
611 && !strcmp(a->actions, b->actions));
612}
613
614static void
615ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
616 enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
617 char *match, char *actions)
bd39395f 618{
5868eb24
BP
619 lflow->od = od;
620 lflow->pipeline = pipeline;
621 lflow->table_id = table_id;
622 lflow->priority = priority;
623 lflow->match = match;
624 lflow->actions = actions;
bd39395f
BP
625}
626
091e3af9
JP
627static const char *
628ingress_stage_to_str(int stage) {
629 switch (stage) {
630#define INGRESS_STAGE(NAME, STR) case S_IN_##NAME: return #STR;
631 INGRESS_STAGES
632#undef INGRESS_STAGE
633 default: return "<unknown>";
634 }
635}
636
637static const char *
638egress_stage_to_str(int stage) {
639 switch (stage) {
640#define EGRESS_STAGE(NAME, STR) case S_OUT_##NAME: return #STR;
641 EGRESS_STAGES
642#undef EGRESS_STAGE
643 default: return "<unknown>";
644 }
645}
646
48605550 647/* Adds a row with the specified contents to the Logical_Flow table. */
bd39395f 648static void
5868eb24
BP
649ovn_lflow_add(struct hmap *lflow_map, struct ovn_datapath *od,
650 enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
651 const char *match, const char *actions)
652{
653 struct ovn_lflow *lflow = xmalloc(sizeof *lflow);
654 ovn_lflow_init(lflow, od, pipeline, table_id, priority,
655 xstrdup(match), xstrdup(actions));
656 hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow));
657}
658
659static struct ovn_lflow *
660ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od,
661 enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
662 const char *match, const char *actions)
663{
664 struct ovn_lflow target;
665 ovn_lflow_init(&target, od, pipeline, table_id, priority,
666 CONST_CAST(char *, match), CONST_CAST(char *, actions));
667
668 struct ovn_lflow *lflow;
669 HMAP_FOR_EACH_WITH_HASH (lflow, hmap_node, ovn_lflow_hash(&target),
670 lflows) {
671 if (ovn_lflow_equal(lflow, &target)) {
672 return lflow;
bd39395f
BP
673 }
674 }
5868eb24
BP
675 return NULL;
676}
bd39395f 677
5868eb24
BP
678static void
679ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow)
680{
681 if (lflow) {
682 hmap_remove(lflows, &lflow->hmap_node);
683 free(lflow->match);
684 free(lflow->actions);
685 free(lflow);
686 }
bd39395f
BP
687}
688
bd39395f
BP
689/* Appends port security constraints on L2 address field 'eth_addr_field'
690 * (e.g. "eth.src" or "eth.dst") to 'match'. 'port_security', with
691 * 'n_port_security' elements, is the collection of port_security constraints
f7cb14cd 692 * from an OVN_NB Logical_Port row. */
bd39395f
BP
693static void
694build_port_security(const char *eth_addr_field,
695 char **port_security, size_t n_port_security,
696 struct ds *match)
697{
698 size_t base_len = match->length;
699 ds_put_format(match, " && %s == {", eth_addr_field);
700
701 size_t n = 0;
702 for (size_t i = 0; i < n_port_security; i++) {
74ff3298 703 struct eth_addr ea;
f7cb14cd 704
74ff3298 705 if (eth_addr_from_string(port_security[i], &ea)) {
f7cb14cd 706 ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
bd39395f
BP
707 ds_put_char(match, ' ');
708 n++;
709 }
710 }
f7cb14cd 711 ds_chomp(match, ' ');
bd39395f 712 ds_put_cstr(match, "}");
4edcdcf4 713
bd39395f
BP
714 if (!n) {
715 match->length = base_len;
716 }
717}
718
95a9a275
RB
719static bool
720lport_is_enabled(const struct nbrec_logical_port *lport)
721{
722 return !lport->enabled || *lport->enabled;
723}
724
5868eb24
BP
725/* Updates the Logical_Flow and Multicast_Group tables in the OVN_SB database,
726 * constructing their contents based on the OVN_NB database. */
bd39395f 727static void
5868eb24
BP
728build_lflows(struct northd_context *ctx, struct hmap *datapaths,
729 struct hmap *ports)
bd39395f 730{
5868eb24
BP
731 struct hmap lflows = HMAP_INITIALIZER(&lflows);
732 struct hmap mcgroups = HMAP_INITIALIZER(&mcgroups);
bd39395f 733
5868eb24
BP
734 /* Ingress table 0: Admission control framework (priorities 0 and 100). */
735 struct ovn_datapath *od;
736 HMAP_FOR_EACH (od, key_node, datapaths) {
bd39395f 737 /* Logical VLANs not supported. */
091e3af9
JP
738 ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "vlan.present",
739 "drop;");
bd39395f
BP
740
741 /* Broadcast/multicast source address is invalid. */
091e3af9
JP
742 ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 100, "eth.src[40]",
743 "drop;");
bd39395f 744
35060cdc
BP
745 /* Port security flows have priority 50 (see below) and will continue
746 * to the next table if packet source is acceptable. */
bd39395f
BP
747
748 /* Otherwise drop the packet. */
091e3af9 749 ovn_lflow_add(&lflows, od, P_IN, S_IN_PORT_SEC, 0, "1", "drop;");
bd39395f
BP
750 }
751
5868eb24
BP
752 /* Ingress table 0: Ingress port security (priority 50). */
753 struct ovn_port *op;
754 HMAP_FOR_EACH (op, key_node, ports) {
755 struct ds match = DS_EMPTY_INITIALIZER;
756 ds_put_cstr(&match, "inport == ");
757 json_string_escape(op->key, &match);
758 build_port_security("eth.src",
759 op->nb->port_security, op->nb->n_port_security,
760 &match);
091e3af9 761 ovn_lflow_add(&lflows, op->od, P_IN, S_IN_PORT_SEC, 50, ds_cstr(&match),
5868eb24
BP
762 lport_is_enabled(op->nb) ? "next;" : "drop;");
763 ds_destroy(&match);
764 }
445a266a 765
1b19bbb4
JP
766 /* Ingress table 1: ACLs (any priority). */
767 HMAP_FOR_EACH (od, key_node, datapaths) {
768 for (size_t i = 0; i < od->nb->n_acls; i++) {
769 const struct nbrec_acl *acl = od->nb->acls[i];
770 const char *action;
771
772 if (strcmp(acl->direction, "from-lport")) {
773 continue;
774 }
775
776 action = (!strcmp(acl->action, "allow") ||
777 !strcmp(acl->action, "allow-related"))
778 ? "next;" : "drop;";
779 ovn_lflow_add(&lflows, od, P_IN, S_IN_ACL, acl->priority,
780 acl->match, action);
781 }
782 }
783 HMAP_FOR_EACH (od, key_node, datapaths) {
784 ovn_lflow_add(&lflows, od, P_IN, S_IN_ACL, 0, "1", "next;");
785 }
786
787 /* Ingress table 2: Destination lookup, broadcast and multicast handling
5868eb24
BP
788 * (priority 100). */
789 HMAP_FOR_EACH (op, key_node, ports) {
790 if (lport_is_enabled(op->nb)) {
791 ovn_multicast_add(&mcgroups, &mc_flood, op);
445a266a 792 }
5868eb24
BP
793 }
794 HMAP_FOR_EACH (od, key_node, datapaths) {
091e3af9 795 ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 100, "eth.dst[40]",
5868eb24 796 "outport = \""MC_FLOOD"\"; output;");
bd39395f 797 }
bd39395f 798
1b19bbb4 799 /* Ingress table 2: Destination lookup, unicast handling (priority 50), */
5868eb24
BP
800 HMAP_FOR_EACH (op, key_node, ports) {
801 for (size_t i = 0; i < op->nb->n_macs; i++) {
74ff3298 802 struct eth_addr mac;
5868eb24 803
74ff3298 804 if (eth_addr_from_string(op->nb->macs[i], &mac)) {
5868eb24
BP
805 struct ds match, actions;
806
807 ds_init(&match);
808 ds_put_format(&match, "eth.dst == %s", op->nb->macs[i]);
809
810 ds_init(&actions);
811 ds_put_cstr(&actions, "outport = ");
812 json_string_escape(op->nb->name, &actions);
813 ds_put_cstr(&actions, "; output;");
091e3af9 814 ovn_lflow_add(&lflows, op->od, P_IN, S_IN_L2_LKUP, 50,
5868eb24
BP
815 ds_cstr(&match), ds_cstr(&actions));
816 ds_destroy(&actions);
817 ds_destroy(&match);
818 } else if (!strcmp(op->nb->macs[i], "unknown")) {
819 ovn_multicast_add(&mcgroups, &mc_unknown, op);
820 op->od->has_unknown = true;
821 } else {
822 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
445a266a 823
5868eb24
BP
824 VLOG_INFO_RL(&rl, "%s: invalid syntax '%s' in macs column",
825 op->nb->name, op->nb->macs[i]);
445a266a
BP
826 }
827 }
bd39395f
BP
828 }
829
1b19bbb4 830 /* Ingress table 2: Destination lookup for unknown MACs (priority 0). */
5868eb24
BP
831 HMAP_FOR_EACH (od, key_node, datapaths) {
832 if (od->has_unknown) {
091e3af9 833 ovn_lflow_add(&lflows, od, P_IN, S_IN_L2_LKUP, 0, "1",
5868eb24 834 "outport = \""MC_UNKNOWN"\"; output;");
445a266a 835 }
bd39395f
BP
836 }
837
5868eb24
BP
838 /* Egress table 0: ACLs (any priority). */
839 HMAP_FOR_EACH (od, key_node, datapaths) {
840 for (size_t i = 0; i < od->nb->n_acls; i++) {
841 const struct nbrec_acl *acl = od->nb->acls[i];
842 const char *action;
843
1b19bbb4
JP
844 if (strcmp(acl->direction, "to-lport")) {
845 continue;
846 }
847
5868eb24
BP
848 action = (!strcmp(acl->action, "allow") ||
849 !strcmp(acl->action, "allow-related"))
850 ? "next;" : "drop;";
091e3af9
JP
851 ovn_lflow_add(&lflows, od, P_OUT, S_OUT_ACL, acl->priority,
852 acl->match, action);
5868eb24 853 }
48f42f3a 854 }
5868eb24 855 HMAP_FOR_EACH (od, key_node, datapaths) {
091e3af9 856 ovn_lflow_add(&lflows, od, P_OUT, S_OUT_ACL, 0, "1", "next;");
48f42f3a
RB
857 }
858
5868eb24
BP
859 /* Egress table 1: Egress port security multicast/broadcast (priority
860 * 100). */
861 HMAP_FOR_EACH (od, key_node, datapaths) {
091e3af9
JP
862 ovn_lflow_add(&lflows, od, P_OUT, S_OUT_PORT_SEC, 100, "eth.dst[40]",
863 "output;");
48f42f3a
RB
864 }
865
d770a830
BP
866 /* Egress table 1: Egress port security (priorities 50 and 150).
867 *
868 * Priority 50 rules implement port security for enabled logical port.
869 *
870 * Priority 150 rules drop packets to disabled logical ports, so that they
871 * don't even receive multicast or broadcast packets. */
5868eb24
BP
872 HMAP_FOR_EACH (op, key_node, ports) {
873 struct ds match;
48f42f3a 874
5868eb24
BP
875 ds_init(&match);
876 ds_put_cstr(&match, "outport == ");
877 json_string_escape(op->key, &match);
d770a830
BP
878 if (lport_is_enabled(op->nb)) {
879 build_port_security("eth.dst",
880 op->nb->port_security, op->nb->n_port_security,
881 &match);
882 ovn_lflow_add(&lflows, op->od, P_OUT, S_OUT_PORT_SEC, 50,
883 ds_cstr(&match), "output;");
884 } else {
885 ovn_lflow_add(&lflows, op->od, P_OUT, S_OUT_PORT_SEC, 150,
886 ds_cstr(&match), "drop;");
887 }
eb00399e 888
5868eb24 889 ds_destroy(&match);
eb00399e 890 }
eb00399e 891
5868eb24
BP
892 /* Push changes to the Logical_Flow table to database. */
893 const struct sbrec_logical_flow *sbflow, *next_sbflow;
894 SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow, next_sbflow, ctx->ovnsb_idl) {
895 struct ovn_datapath *od
896 = ovn_datapath_from_sbrec(datapaths, sbflow->logical_datapath);
897 if (!od) {
898 sbrec_logical_flow_delete(sbflow);
899 continue;
eb00399e 900 }
eb00399e 901
5868eb24
BP
902 struct ovn_lflow *lflow = ovn_lflow_find(
903 &lflows, od, (!strcmp(sbflow->pipeline, "ingress") ? P_IN : P_OUT),
904 sbflow->table_id, sbflow->priority,
905 sbflow->match, sbflow->actions);
906 if (lflow) {
907 ovn_lflow_destroy(&lflows, lflow);
908 } else {
909 sbrec_logical_flow_delete(sbflow);
4edcdcf4
RB
910 }
911 }
5868eb24
BP
912 struct ovn_lflow *lflow, *next_lflow;
913 HMAP_FOR_EACH_SAFE (lflow, next_lflow, hmap_node, &lflows) {
914 sbflow = sbrec_logical_flow_insert(ctx->ovnsb_txn);
915 sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb);
916 sbrec_logical_flow_set_pipeline(
917 sbflow, lflow->pipeline == P_IN ? "ingress" : "egress");
918 sbrec_logical_flow_set_table_id(sbflow, lflow->table_id);
919 sbrec_logical_flow_set_priority(sbflow, lflow->priority);
920 sbrec_logical_flow_set_match(sbflow, lflow->match);
921 sbrec_logical_flow_set_actions(sbflow, lflow->actions);
091e3af9 922
aaf881c6
BP
923 const struct smap ids = SMAP_CONST1(
924 &ids, "stage-name",
925 (lflow->pipeline == P_IN
926 ? ingress_stage_to_str(lflow->table_id)
927 : egress_stage_to_str(lflow->table_id)));
928 sbrec_logical_flow_set_external_ids(sbflow, &ids);
091e3af9 929
5868eb24 930 ovn_lflow_destroy(&lflows, lflow);
eb00399e 931 }
5868eb24
BP
932 hmap_destroy(&lflows);
933
934 /* Push changes to the Multicast_Group table to database. */
935 const struct sbrec_multicast_group *sbmc, *next_sbmc;
936 SBREC_MULTICAST_GROUP_FOR_EACH_SAFE (sbmc, next_sbmc, ctx->ovnsb_idl) {
937 struct ovn_datapath *od = ovn_datapath_from_sbrec(datapaths,
938 sbmc->datapath);
939 if (!od) {
940 sbrec_multicast_group_delete(sbmc);
941 continue;
942 }
eb00399e 943
5868eb24
BP
944 struct multicast_group group = { .name = sbmc->name,
945 .key = sbmc->tunnel_key };
946 struct ovn_multicast *mc = ovn_multicast_find(&mcgroups, od, &group);
947 if (mc) {
948 ovn_multicast_update_sbrec(mc, sbmc);
949 ovn_multicast_destroy(&mcgroups, mc);
950 } else {
951 sbrec_multicast_group_delete(sbmc);
952 }
953 }
954 struct ovn_multicast *mc, *next_mc;
955 HMAP_FOR_EACH_SAFE (mc, next_mc, hmap_node, &mcgroups) {
956 sbmc = sbrec_multicast_group_insert(ctx->ovnsb_txn);
957 sbrec_multicast_group_set_datapath(sbmc, mc->datapath->sb);
958 sbrec_multicast_group_set_name(sbmc, mc->group->name);
959 sbrec_multicast_group_set_tunnel_key(sbmc, mc->group->key);
960 ovn_multicast_update_sbrec(mc, sbmc);
961 ovn_multicast_destroy(&mcgroups, mc);
4edcdcf4 962 }
5868eb24 963 hmap_destroy(&mcgroups);
4edcdcf4 964}
5868eb24 965\f
4edcdcf4 966static void
2e2762d4 967ovnnb_db_changed(struct northd_context *ctx)
4edcdcf4 968{
c29734fc 969 VLOG_DBG("ovn-nb db contents have changed.");
4edcdcf4 970
5868eb24
BP
971 struct hmap datapaths, ports;
972 build_datapaths(ctx, &datapaths);
973 build_ports(ctx, &datapaths, &ports);
974 build_lflows(ctx, &datapaths, &ports);
975
976 struct ovn_datapath *dp, *next_dp;
977 HMAP_FOR_EACH_SAFE (dp, next_dp, key_node, &datapaths) {
978 ovn_datapath_destroy(&datapaths, dp);
979 }
980 hmap_destroy(&datapaths);
981
982 struct ovn_port *port, *next_port;
983 HMAP_FOR_EACH_SAFE (port, next_port, key_node, &ports) {
984 ovn_port_destroy(&ports, port);
985 }
986 hmap_destroy(&ports);
ac0630a2
RB
987}
988
f93818dd
RB
989/*
990 * The only change we get notified about is if the 'chassis' column of the
dcda6e0d
BP
991 * 'Port_Binding' table changes. When this column is not empty, it means we
992 * need to set the corresponding logical port as 'up' in the northbound DB.
f93818dd 993 */
ac0630a2 994static void
2e2762d4 995ovnsb_db_changed(struct northd_context *ctx)
ac0630a2 996{
fc3113bc 997 struct hmap lports_hmap;
5868eb24
BP
998 const struct sbrec_port_binding *sb;
999 const struct nbrec_logical_port *nb;
fc3113bc
RB
1000
1001 struct lport_hash_node {
1002 struct hmap_node node;
5868eb24 1003 const struct nbrec_logical_port *nb;
fc3113bc 1004 } *hash_node, *hash_node_next;
f93818dd
RB
1005
1006 VLOG_DBG("Recalculating port up states for ovn-nb db.");
1007
fc3113bc 1008 hmap_init(&lports_hmap);
f93818dd 1009
5868eb24 1010 NBREC_LOGICAL_PORT_FOR_EACH(nb, ctx->ovnnb_idl) {
fc3113bc 1011 hash_node = xzalloc(sizeof *hash_node);
5868eb24
BP
1012 hash_node->nb = nb;
1013 hmap_insert(&lports_hmap, &hash_node->node, hash_string(nb->name, 0));
fc3113bc
RB
1014 }
1015
5868eb24
BP
1016 SBREC_PORT_BINDING_FOR_EACH(sb, ctx->ovnsb_idl) {
1017 nb = NULL;
fc3113bc 1018 HMAP_FOR_EACH_WITH_HASH(hash_node, node,
5868eb24
BP
1019 hash_string(sb->logical_port, 0),
1020 &lports_hmap) {
1021 if (!strcmp(sb->logical_port, hash_node->nb->name)) {
1022 nb = hash_node->nb;
fc3113bc
RB
1023 break;
1024 }
f93818dd
RB
1025 }
1026
5868eb24 1027 if (!nb) {
dcda6e0d 1028 /* The logical port doesn't exist for this port binding. This can
2e2762d4 1029 * happen under normal circumstances when ovn-northd hasn't gotten
dcda6e0d 1030 * around to pruning the Port_Binding yet. */
f93818dd
RB
1031 continue;
1032 }
1033
5868eb24 1034 if (sb->chassis && (!nb->up || !*nb->up)) {
f93818dd 1035 bool up = true;
5868eb24
BP
1036 nbrec_logical_port_set_up(nb, &up, 1);
1037 } else if (!sb->chassis && (!nb->up || *nb->up)) {
f93818dd 1038 bool up = false;
5868eb24 1039 nbrec_logical_port_set_up(nb, &up, 1);
f93818dd
RB
1040 }
1041 }
fc3113bc
RB
1042
1043 HMAP_FOR_EACH_SAFE(hash_node, hash_node_next, node, &lports_hmap) {
1044 hmap_remove(&lports_hmap, &hash_node->node);
1045 free(hash_node);
1046 }
1047 hmap_destroy(&lports_hmap);
ac0630a2
RB
1048}
1049\f
45f98d4c
RB
1050
1051static char *default_db_;
1052
ac0630a2
RB
1053static const char *
1054default_db(void)
1055{
45f98d4c
RB
1056 if (!default_db_) {
1057 default_db_ = xasprintf("unix:%s/db.sock", ovs_rundir());
ac0630a2 1058 }
45f98d4c 1059 return default_db_;
ac0630a2
RB
1060}
1061
1062static void
1063parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1064{
1065 enum {
67d9b930 1066 DAEMON_OPTION_ENUMS,
ac0630a2
RB
1067 VLOG_OPTION_ENUMS,
1068 };
1069 static const struct option long_options[] = {
ec78987f 1070 {"ovnsb-db", required_argument, NULL, 'd'},
ac0630a2
RB
1071 {"ovnnb-db", required_argument, NULL, 'D'},
1072 {"help", no_argument, NULL, 'h'},
1073 {"options", no_argument, NULL, 'o'},
1074 {"version", no_argument, NULL, 'V'},
67d9b930 1075 DAEMON_LONG_OPTIONS,
ac0630a2
RB
1076 VLOG_LONG_OPTIONS,
1077 STREAM_SSL_LONG_OPTIONS,
1078 {NULL, 0, NULL, 0},
1079 };
1080 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
1081
1082 for (;;) {
1083 int c;
1084
1085 c = getopt_long(argc, argv, short_options, long_options, NULL);
1086 if (c == -1) {
1087 break;
1088 }
1089
1090 switch (c) {
67d9b930 1091 DAEMON_OPTION_HANDLERS;
ac0630a2
RB
1092 VLOG_OPTION_HANDLERS;
1093 STREAM_SSL_OPTION_HANDLERS;
1094
1095 case 'd':
ec78987f 1096 ovnsb_db = optarg;
ac0630a2
RB
1097 break;
1098
1099 case 'D':
1100 ovnnb_db = optarg;
1101 break;
1102
1103 case 'h':
1104 usage();
1105 exit(EXIT_SUCCESS);
1106
1107 case 'o':
1108 ovs_cmdl_print_options(long_options);
1109 exit(EXIT_SUCCESS);
1110
1111 case 'V':
1112 ovs_print_version(0, 0);
1113 exit(EXIT_SUCCESS);
1114
1115 default:
1116 break;
1117 }
1118 }
1119
ec78987f
JP
1120 if (!ovnsb_db) {
1121 ovnsb_db = default_db();
ac0630a2
RB
1122 }
1123
1124 if (!ovnnb_db) {
1125 ovnnb_db = default_db();
1126 }
1127
1128 free(short_options);
1129}
1130
5868eb24
BP
1131static void
1132add_column_noalert(struct ovsdb_idl *idl,
1133 const struct ovsdb_idl_column *column)
1134{
1135 ovsdb_idl_add_column(idl, column);
1136 ovsdb_idl_omit_alert(idl, column);
1137}
1138
ac0630a2
RB
1139int
1140main(int argc, char *argv[])
1141{
1142 extern struct vlog_module VLM_reconnect;
ec78987f 1143 struct ovsdb_idl *ovnnb_idl, *ovnsb_idl;
ac0630a2
RB
1144 unsigned int ovnnb_seqno, ovn_seqno;
1145 int res = EXIT_SUCCESS;
2e2762d4 1146 struct northd_context ctx = {
3c78b3ca 1147 .ovnsb_txn = NULL,
f93818dd
RB
1148 };
1149 bool ovnnb_changes_pending = false;
1150 bool ovn_changes_pending = false;
7b303ff9
AW
1151 struct unixctl_server *unixctl;
1152 int retval;
1153 bool exiting;
ac0630a2
RB
1154
1155 fatal_ignore_sigpipe();
1156 set_program_name(argv[0]);
485f0696 1157 service_start(&argc, &argv);
ac0630a2
RB
1158 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
1159 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
1160 parse_options(argc, argv);
67d9b930 1161
7b303ff9
AW
1162 daemonize_start();
1163
1164 retval = unixctl_server_create(NULL, &unixctl);
1165 if (retval) {
1166 exit(EXIT_FAILURE);
1167 }
1168 unixctl_command_register("exit", "", 0, 0, ovn_northd_exit, &exiting);
1169
1170 daemonize_complete();
67d9b930 1171
ac0630a2 1172 nbrec_init();
ec78987f 1173 sbrec_init();
ac0630a2
RB
1174
1175 /* We want to detect all changes to the ovn-nb db. */
f93818dd
RB
1176 ctx.ovnnb_idl = ovnnb_idl = ovsdb_idl_create(ovnnb_db,
1177 &nbrec_idl_class, true, true);
ac0630a2 1178
ec78987f
JP
1179 ctx.ovnsb_idl = ovnsb_idl = ovsdb_idl_create(ovnsb_db,
1180 &sbrec_idl_class, false, true);
5868eb24
BP
1181
1182 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_logical_flow);
1183 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_logical_datapath);
1184 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_pipeline);
1185 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_table_id);
1186 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_priority);
1187 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_match);
1188 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_actions);
1189
1190 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_multicast_group);
1191 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_datapath);
1192 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_tunnel_key);
1193 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_name);
1194 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_ports);
1195
1196 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_datapath_binding);
1197 add_column_noalert(ovnsb_idl, &sbrec_datapath_binding_col_tunnel_key);
1198 add_column_noalert(ovnsb_idl, &sbrec_datapath_binding_col_external_ids);
1199
dcda6e0d 1200 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_port_binding);
5868eb24
BP
1201 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_datapath);
1202 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_logical_port);
1203 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_tunnel_key);
1204 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_parent_port);
1205 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_tag);
1206 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_type);
1207 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_options);
1208 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_mac);
dcda6e0d 1209 ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_chassis);
ac0630a2
RB
1210
1211 /*
1212 * The loop here just runs the IDL in a loop waiting for the seqno to
1213 * change, which indicates that the contents of the db have changed.
1214 *
a0149f47
JP
1215 * If the contents of the ovn-nb db change, the mappings to the ovn-sb
1216 * db must be recalculated.
ac0630a2 1217 *
a0149f47 1218 * If the contents of the ovn-sb db change, it means the 'up' state of
91ae2065 1219 * a port may have changed, as that's the only type of change ovn-northd is
a0149f47 1220 * watching for.
ac0630a2
RB
1221 */
1222
1223 ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl);
ec78987f 1224 ovn_seqno = ovsdb_idl_get_seqno(ovnsb_idl);
7b303ff9
AW
1225 exiting = false;
1226 while (!exiting) {
ac0630a2 1227 ovsdb_idl_run(ovnnb_idl);
ec78987f 1228 ovsdb_idl_run(ovnsb_idl);
7b303ff9 1229 unixctl_server_run(unixctl);
ac0630a2
RB
1230
1231 if (!ovsdb_idl_is_alive(ovnnb_idl)) {
1232 int retval = ovsdb_idl_get_last_error(ovnnb_idl);
1233 VLOG_ERR("%s: database connection failed (%s)",
1234 ovnnb_db, ovs_retval_to_string(retval));
1235 res = EXIT_FAILURE;
1236 break;
1237 }
1238
ec78987f
JP
1239 if (!ovsdb_idl_is_alive(ovnsb_idl)) {
1240 int retval = ovsdb_idl_get_last_error(ovnsb_idl);
ac0630a2 1241 VLOG_ERR("%s: database connection failed (%s)",
ec78987f 1242 ovnsb_db, ovs_retval_to_string(retval));
ac0630a2
RB
1243 res = EXIT_FAILURE;
1244 break;
1245 }
1246
1247 if (ovnnb_seqno != ovsdb_idl_get_seqno(ovnnb_idl)) {
1248 ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl);
f93818dd 1249 ovnnb_changes_pending = true;
ac0630a2
RB
1250 }
1251
ec78987f
JP
1252 if (ovn_seqno != ovsdb_idl_get_seqno(ovnsb_idl)) {
1253 ovn_seqno = ovsdb_idl_get_seqno(ovnsb_idl);
f93818dd
RB
1254 ovn_changes_pending = true;
1255 }
1256
1257 /*
1258 * If there are any pending changes, we delay recalculating the
1259 * necessary updates until after an existing transaction finishes.
91ae2065
RB
1260 * This avoids the possibility of rapid updates causing ovn-northd to
1261 * never be able to successfully make the corresponding updates to the
1262 * other db. Instead, pending changes are batched up until the next
1263 * time we get a chance to calculate the new state and apply it.
f93818dd
RB
1264 */
1265
3c78b3ca 1266 if (ovnnb_changes_pending && !ctx.ovnsb_txn) {
f93818dd
RB
1267 /*
1268 * The OVN-nb db contents have changed, so create a transaction for
a0149f47 1269 * updating the OVN-sb DB.
f93818dd 1270 */
3c78b3ca 1271 ctx.ovnsb_txn = ovsdb_idl_txn_create(ctx.ovnsb_idl);
5da82071 1272 ovsdb_idl_txn_add_comment(ctx.ovnsb_txn,
91ae2065 1273 "ovn-northd: northbound db changed");
f93818dd
RB
1274 ovnnb_db_changed(&ctx);
1275 ovnnb_changes_pending = false;
1276 }
1277
1278 if (ovn_changes_pending && !ctx.ovnnb_txn) {
1279 /*
a0149f47 1280 * The OVN-sb db contents have changed, so create a transaction for
f93818dd
RB
1281 * updating the northbound DB.
1282 */
1283 ctx.ovnnb_txn = ovsdb_idl_txn_create(ctx.ovnnb_idl);
5da82071 1284 ovsdb_idl_txn_add_comment(ctx.ovnnb_txn,
91ae2065 1285 "ovn-northd: southbound db changed");
ec78987f 1286 ovnsb_db_changed(&ctx);
f93818dd
RB
1287 ovn_changes_pending = false;
1288 }
1289
1290 if (ctx.ovnnb_txn) {
1291 enum ovsdb_idl_txn_status txn_status;
1292 txn_status = ovsdb_idl_txn_commit(ctx.ovnnb_txn);
1293 switch (txn_status) {
1294 case TXN_UNCOMMITTED:
1295 case TXN_INCOMPLETE:
1296 /* Come back around and try to commit this transaction again */
1297 break;
1298 case TXN_ABORTED:
1299 case TXN_TRY_AGAIN:
1300 case TXN_NOT_LOCKED:
1301 case TXN_ERROR:
1302 /* Something went wrong, so try creating a new transaction. */
1303 ovn_changes_pending = true;
1304 case TXN_UNCHANGED:
1305 case TXN_SUCCESS:
1306 ovsdb_idl_txn_destroy(ctx.ovnnb_txn);
1307 ctx.ovnnb_txn = NULL;
1308 }
1309 }
1310
3c78b3ca 1311 if (ctx.ovnsb_txn) {
f93818dd 1312 enum ovsdb_idl_txn_status txn_status;
3c78b3ca 1313 txn_status = ovsdb_idl_txn_commit(ctx.ovnsb_txn);
f93818dd
RB
1314 switch (txn_status) {
1315 case TXN_UNCOMMITTED:
1316 case TXN_INCOMPLETE:
1317 /* Come back around and try to commit this transaction again */
1318 break;
1319 case TXN_ABORTED:
1320 case TXN_TRY_AGAIN:
1321 case TXN_NOT_LOCKED:
1322 case TXN_ERROR:
1323 /* Something went wrong, so try creating a new transaction. */
1324 ovnnb_changes_pending = true;
1325 case TXN_UNCHANGED:
1326 case TXN_SUCCESS:
3c78b3ca
JP
1327 ovsdb_idl_txn_destroy(ctx.ovnsb_txn);
1328 ctx.ovnsb_txn = NULL;
f93818dd 1329 }
ac0630a2
RB
1330 }
1331
1332 if (ovnnb_seqno == ovsdb_idl_get_seqno(ovnnb_idl) &&
ec78987f 1333 ovn_seqno == ovsdb_idl_get_seqno(ovnsb_idl)) {
ac0630a2 1334 ovsdb_idl_wait(ovnnb_idl);
ec78987f 1335 ovsdb_idl_wait(ovnsb_idl);
f93818dd
RB
1336 if (ctx.ovnnb_txn) {
1337 ovsdb_idl_txn_wait(ctx.ovnnb_txn);
1338 }
3c78b3ca
JP
1339 if (ctx.ovnsb_txn) {
1340 ovsdb_idl_txn_wait(ctx.ovnsb_txn);
f93818dd 1341 }
7b303ff9
AW
1342 unixctl_server_wait(unixctl);
1343 if (exiting) {
1344 poll_immediate_wake();
1345 }
ac0630a2
RB
1346 poll_block();
1347 }
485f0696
GS
1348 if (should_service_stop()) {
1349 exiting = true;
1350 }
ac0630a2
RB
1351 }
1352
7b303ff9 1353 unixctl_server_destroy(unixctl);
ec78987f 1354 ovsdb_idl_destroy(ovnsb_idl);
ac0630a2 1355 ovsdb_idl_destroy(ovnnb_idl);
485f0696 1356 service_stop();
ac0630a2 1357
45f98d4c
RB
1358 free(default_db_);
1359
ac0630a2
RB
1360 exit(res);
1361}
7b303ff9
AW
1362
1363static void
1364ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
1365 const char *argv[] OVS_UNUSED, void *exiting_)
1366{
1367 bool *exiting = exiting_;
1368 *exiting = true;
1369
1370 unixctl_command_reply(conn, NULL);
1371}