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