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:
6 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "command-line.h"
24 #include "dynamic-string.h"
25 #include "fatal-signal.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"
35 #include "stream-ssl.h"
39 #include "openvswitch/vlog.h"
41 VLOG_DEFINE_THIS_MODULE(ovn_northd);
43 static unixctl_cb_func ovn_northd_exit;
45 struct northd_context {
46 struct ovsdb_idl *ovnnb_idl;
47 struct ovsdb_idl *ovnsb_idl;
48 struct ovsdb_idl_txn *ovnnb_txn;
49 struct ovsdb_idl_txn *ovnsb_txn;
52 static const char *ovnnb_db;
53 static const char *ovnsb_db;
55 static const char *default_db(void);
61 %s: OVN northbound management daemon\n\
62 usage: %s [OPTIONS]\n\
65 --ovnnb-db=DATABASE connect to ovn-nb database at DATABASE\n\
67 --ovnsb-db=DATABASE connect to ovn-sb database at DATABASE\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());
75 stream_usage("database", true, true, false);
79 struct hmap_node hmap_node;
84 destroy_tnlids(struct hmap *tnlids)
86 struct tnlid_node *node, *next;
87 HMAP_FOR_EACH_SAFE (node, next, hmap_node, tnlids) {
88 hmap_remove(tnlids, &node->hmap_node);
95 add_tnlid(struct hmap *set, uint32_t tnlid)
97 struct tnlid_node *node = xmalloc(sizeof *node);
98 hmap_insert(set, &node->hmap_node, hash_int(tnlid, 0));
103 tnlid_in_use(const struct hmap *set, uint32_t tnlid)
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) {
115 allocate_tnlid(struct hmap *set, const char *name, uint32_t max,
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);
127 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
128 VLOG_WARN_RL(&rl, "all %s tunnel ids exhausted", name);
132 /* The 'key' comes from nb->header_.uuid or sb->external_ids:logical-switch. */
133 struct ovn_datapath {
134 struct hmap_node key_node; /* Index on 'key'. */
135 struct uuid key; /* nb->header_.uuid. */
137 const struct nbrec_logical_switch *nb; /* May be NULL. */
138 const struct sbrec_datapath_binding *sb; /* May be NULL. */
140 struct ovs_list list; /* In list of similar records. */
142 struct hmap port_tnlids;
143 uint32_t port_key_hint;
148 static struct ovn_datapath *
149 ovn_datapath_create(struct hmap *datapaths, const struct uuid *key,
150 const struct nbrec_logical_switch *nb,
151 const struct sbrec_datapath_binding *sb)
153 struct ovn_datapath *od = xzalloc(sizeof *od);
157 hmap_init(&od->port_tnlids);
158 od->port_key_hint = 0;
159 hmap_insert(datapaths, &od->key_node, uuid_hash(&od->key));
164 ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *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
170 hmap_remove(datapaths, &od->key_node);
171 destroy_tnlids(&od->port_tnlids);
176 static struct ovn_datapath *
177 ovn_datapath_find(struct hmap *datapaths, const struct uuid *uuid)
179 struct ovn_datapath *od;
181 HMAP_FOR_EACH_WITH_HASH (od, key_node, uuid_hash(uuid), datapaths) {
182 if (uuid_equals(uuid, &od->key)) {
189 static struct ovn_datapath *
190 ovn_datapath_from_sbrec(struct hmap *datapaths,
191 const struct sbrec_datapath_binding *sb)
195 if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key)) {
198 return ovn_datapath_find(datapaths, &key);
202 join_datapaths(struct northd_context *ctx, struct hmap *datapaths,
203 struct ovs_list *sb_only, struct ovs_list *nb_only,
204 struct ovs_list *both)
206 hmap_init(datapaths);
211 const struct sbrec_datapath_binding *sb, *sb_next;
212 SBREC_DATAPATH_BINDING_FOR_EACH_SAFE (sb, sb_next, ctx->ovnsb_idl) {
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);
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);
232 struct ovn_datapath *od = ovn_datapath_create(datapaths, &key,
234 list_push_back(sb_only, &od->list);
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,
243 list_remove(&od->list);
244 list_push_back(both, &od->list);
246 od = ovn_datapath_create(datapaths, &nb->header_.uuid, nb, NULL);
247 list_push_back(nb_only, &od->list);
253 ovn_datapath_allocate_key(struct hmap *dp_tnlids)
255 static uint32_t hint;
256 return allocate_tnlid(dp_tnlids, "datapath", (1u << 24) - 1, &hint);
260 build_datapaths(struct northd_context *ctx, struct hmap *datapaths)
262 struct ovs_list sb_only, nb_only, both;
264 join_datapaths(ctx, datapaths, &sb_only, &nb_only, &both);
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);
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);
281 od->sb = sbrec_datapath_binding_insert(ctx->ovnsb_txn);
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);
290 sbrec_datapath_binding_set_tunnel_key(od->sb, tunnel_key);
292 destroy_tnlids(&dp_tnlids);
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);
305 struct hmap_node key_node; /* Index on 'key'. */
306 const char *key; /* nb->name and sb->logical_port */
308 const struct nbrec_logical_port *nb; /* May be NULL. */
309 const struct sbrec_port_binding *sb; /* May be NULL. */
311 struct ovn_datapath *od;
313 struct ovs_list list; /* In list of similar records. */
316 static struct ovn_port *
317 ovn_port_create(struct hmap *ports, const char *key,
318 const struct nbrec_logical_port *nb,
319 const struct sbrec_port_binding *sb)
321 struct ovn_port *op = xzalloc(sizeof *op);
325 hmap_insert(ports, &op->key_node, hash_string(op->key, 0));
330 ovn_port_destroy(struct hmap *ports, struct ovn_port *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
336 hmap_remove(ports, &port->key_node);
341 static struct ovn_port *
342 ovn_port_find(struct hmap *ports, const char *name)
346 HMAP_FOR_EACH_WITH_HASH (op, key_node, hash_string(name, 0), ports) {
347 if (!strcmp(op->key, name)) {
355 ovn_port_allocate_key(struct ovn_datapath *od)
357 return allocate_tnlid(&od->port_tnlids, "port",
358 (1u << 15) - 1, &od->port_key_hint);
362 join_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)
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,
376 list_push_back(sb_only, &op->list);
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);
386 list_remove(&op->list);
387 list_push_back(both, &op->list);
389 op = ovn_port_create(ports, nb->name, nb, NULL);
390 list_push_back(nb_only, &op->list);
398 ovn_port_update_sbrec(const struct ovn_port *op)
400 sbrec_port_binding_set_type(op->sb, op->nb->type);
401 sbrec_port_binding_set_options(op->sb, &op->nb->options);
402 sbrec_port_binding_set_datapath(op->sb, op->od->sb);
403 sbrec_port_binding_set_parent_port(op->sb, op->nb->parent_name);
404 sbrec_port_binding_set_tag(op->sb, op->nb->tag, op->nb->n_tag);
405 sbrec_port_binding_set_mac(op->sb, (const char **) op->nb->macs,
410 build_ports(struct northd_context *ctx, struct hmap *datapaths,
413 struct ovs_list sb_only, nb_only, both;
415 join_logical_ports(ctx, datapaths, ports, &sb_only, &nb_only, &both);
417 /* For logical ports that are in both databases, update the southbound
418 * record based on northbound data. Also index the in-use tunnel_keys. */
419 struct ovn_port *op, *next;
420 LIST_FOR_EACH_SAFE (op, next, list, &both) {
421 ovn_port_update_sbrec(op);
423 add_tnlid(&op->od->port_tnlids, op->sb->tunnel_key);
424 if (op->sb->tunnel_key > op->od->port_key_hint) {
425 op->od->port_key_hint = op->sb->tunnel_key;
429 /* Add southbound record for each unmatched northbound record. */
430 LIST_FOR_EACH_SAFE (op, next, list, &nb_only) {
431 uint16_t tunnel_key = ovn_port_allocate_key(op->od);
436 op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn);
437 ovn_port_update_sbrec(op);
439 sbrec_port_binding_set_logical_port(op->sb, op->key);
440 sbrec_port_binding_set_tunnel_key(op->sb, tunnel_key);
443 /* Delete southbound records without northbound matches. */
444 LIST_FOR_EACH_SAFE(op, next, list, &sb_only) {
445 list_remove(&op->list);
446 sbrec_port_binding_delete(op->sb);
447 ovn_port_destroy(ports, op);
451 #define OVN_MIN_MULTICAST 32768
452 #define OVN_MAX_MULTICAST 65535
454 struct multicast_group {
456 uint16_t key; /* OVN_MIN_MULTICAST...OVN_MAX_MULTICAST. */
459 #define MC_FLOOD "_MC_flood"
460 static const struct multicast_group mc_flood = { MC_FLOOD, 65535 };
462 #define MC_UNKNOWN "_MC_unknown"
463 static const struct multicast_group mc_unknown = { MC_UNKNOWN, 65534 };
466 multicast_group_equal(const struct multicast_group *a,
467 const struct multicast_group *b)
469 return !strcmp(a->name, b->name) && a->key == b->key;
472 /* Multicast group entry. */
473 struct ovn_multicast {
474 struct hmap_node hmap_node; /* Index on 'datapath' and 'key'. */
475 struct ovn_datapath *datapath;
476 const struct multicast_group *group;
478 struct ovn_port **ports;
479 size_t n_ports, allocated_ports;
483 ovn_multicast_hash(const struct ovn_datapath *datapath,
484 const struct multicast_group *group)
486 return hash_pointer(datapath, group->key);
489 static struct ovn_multicast *
490 ovn_multicast_find(struct hmap *mcgroups, struct ovn_datapath *datapath,
491 const struct multicast_group *group)
493 struct ovn_multicast *mc;
495 HMAP_FOR_EACH_WITH_HASH (mc, hmap_node,
496 ovn_multicast_hash(datapath, group), mcgroups) {
497 if (mc->datapath == datapath
498 && multicast_group_equal(mc->group, group)) {
506 ovn_multicast_add(struct hmap *mcgroups, const struct multicast_group *group,
507 struct ovn_port *port)
509 struct ovn_datapath *od = port->od;
510 struct ovn_multicast *mc = ovn_multicast_find(mcgroups, od, group);
512 mc = xmalloc(sizeof *mc);
513 hmap_insert(mcgroups, &mc->hmap_node, ovn_multicast_hash(od, group));
517 mc->allocated_ports = 4;
518 mc->ports = xmalloc(mc->allocated_ports * sizeof *mc->ports);
520 if (mc->n_ports >= mc->allocated_ports) {
521 mc->ports = x2nrealloc(mc->ports, &mc->allocated_ports,
524 mc->ports[mc->n_ports++] = port;
528 ovn_multicast_destroy(struct hmap *mcgroups, struct ovn_multicast *mc)
531 hmap_remove(mcgroups, &mc->hmap_node);
538 ovn_multicast_update_sbrec(const struct ovn_multicast *mc,
539 const struct sbrec_multicast_group *sb)
541 struct sbrec_port_binding **ports = xmalloc(mc->n_ports * sizeof *ports);
542 for (size_t i = 0; i < mc->n_ports; i++) {
543 ports[i] = CONST_CAST(struct sbrec_port_binding *, mc->ports[i]->sb);
545 sbrec_multicast_group_set_ports(sb, ports, mc->n_ports);
549 /* Logical flow generation.
551 * This code generates the Logical_Flow table in the southbound database, as a
552 * function of most of the northbound database.
556 struct hmap_node hmap_node;
558 struct ovn_datapath *od;
559 enum ovn_pipeline { P_IN, P_OUT } pipeline;
567 ovn_lflow_hash(const struct ovn_lflow *lflow)
569 size_t hash = uuid_hash(&lflow->od->key);
570 hash = hash_2words((lflow->table_id << 16) | lflow->priority, hash);
571 hash = hash_string(lflow->match, hash);
572 return hash_string(lflow->actions, hash);
576 ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b)
578 return (a->od == b->od
579 && a->pipeline == b->pipeline
580 && a->table_id == b->table_id
581 && a->priority == b->priority
582 && !strcmp(a->match, b->match)
583 && !strcmp(a->actions, b->actions));
587 ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
588 enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
589 char *match, char *actions)
592 lflow->pipeline = pipeline;
593 lflow->table_id = table_id;
594 lflow->priority = priority;
595 lflow->match = match;
596 lflow->actions = actions;
599 /* Adds a row with the specified contents to the Logical_Flow table. */
601 ovn_lflow_add(struct hmap *lflow_map, struct ovn_datapath *od,
602 enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
603 const char *match, const char *actions)
605 struct ovn_lflow *lflow = xmalloc(sizeof *lflow);
606 ovn_lflow_init(lflow, od, pipeline, table_id, priority,
607 xstrdup(match), xstrdup(actions));
608 hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow));
611 static struct ovn_lflow *
612 ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od,
613 enum ovn_pipeline pipeline, uint8_t table_id, uint16_t priority,
614 const char *match, const char *actions)
616 struct ovn_lflow target;
617 ovn_lflow_init(&target, od, pipeline, table_id, priority,
618 CONST_CAST(char *, match), CONST_CAST(char *, actions));
620 struct ovn_lflow *lflow;
621 HMAP_FOR_EACH_WITH_HASH (lflow, hmap_node, ovn_lflow_hash(&target),
623 if (ovn_lflow_equal(lflow, &target)) {
631 ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow)
634 hmap_remove(lflows, &lflow->hmap_node);
636 free(lflow->actions);
641 /* Appends port security constraints on L2 address field 'eth_addr_field'
642 * (e.g. "eth.src" or "eth.dst") to 'match'. 'port_security', with
643 * 'n_port_security' elements, is the collection of port_security constraints
644 * from an OVN_NB Logical_Port row. */
646 build_port_security(const char *eth_addr_field,
647 char **port_security, size_t n_port_security,
650 size_t base_len = match->length;
651 ds_put_format(match, " && %s == {", eth_addr_field);
654 for (size_t i = 0; i < n_port_security; i++) {
655 uint8_t ea[ETH_ADDR_LEN];
657 if (eth_addr_from_string(port_security[i], ea)) {
658 ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
659 ds_put_char(match, ' ');
663 ds_chomp(match, ' ');
664 ds_put_cstr(match, "}");
667 match->length = base_len;
672 lport_is_enabled(const struct nbrec_logical_port *lport)
674 return !lport->enabled || *lport->enabled;
677 /* Updates the Logical_Flow and Multicast_Group tables in the OVN_SB database,
678 * constructing their contents based on the OVN_NB database. */
680 build_lflows(struct northd_context *ctx, struct hmap *datapaths,
683 struct hmap lflows = HMAP_INITIALIZER(&lflows);
684 struct hmap mcgroups = HMAP_INITIALIZER(&mcgroups);
686 /* Ingress table 0: Admission control framework (priorities 0 and 100). */
687 struct ovn_datapath *od;
688 HMAP_FOR_EACH (od, key_node, datapaths) {
689 /* Logical VLANs not supported. */
690 ovn_lflow_add(&lflows, od, P_IN, 0, 100, "vlan.present", "drop;");
692 /* Broadcast/multicast source address is invalid. */
693 ovn_lflow_add(&lflows, od, P_IN, 0, 100, "eth.src[40]", "drop;");
695 /* Port security flows have priority 50 (see below) and will continue
696 * to the next table if packet source is acceptable. */
698 /* Otherwise drop the packet. */
699 ovn_lflow_add(&lflows, od, P_IN, 0, 0, "1", "drop;");
702 /* Ingress table 0: Ingress port security (priority 50). */
704 HMAP_FOR_EACH (op, key_node, ports) {
705 struct ds match = DS_EMPTY_INITIALIZER;
706 ds_put_cstr(&match, "inport == ");
707 json_string_escape(op->key, &match);
708 build_port_security("eth.src",
709 op->nb->port_security, op->nb->n_port_security,
711 ovn_lflow_add(&lflows, op->od, P_IN, 0, 50, ds_cstr(&match),
712 lport_is_enabled(op->nb) ? "next;" : "drop;");
716 /* Ingress table 1: Destination lookup, broadcast and multicast handling
718 HMAP_FOR_EACH (op, key_node, ports) {
719 if (lport_is_enabled(op->nb)) {
720 ovn_multicast_add(&mcgroups, &mc_flood, op);
723 HMAP_FOR_EACH (od, key_node, datapaths) {
724 ovn_lflow_add(&lflows, od, P_IN, 1, 100, "eth.dst[40]",
725 "outport = \""MC_FLOOD"\"; output;");
728 /* Ingress table 1: Destination lookup, unicast handling (priority 50), */
729 HMAP_FOR_EACH (op, key_node, ports) {
730 for (size_t i = 0; i < op->nb->n_macs; i++) {
731 uint8_t mac[ETH_ADDR_LEN];
733 if (eth_addr_from_string(op->nb->macs[i], mac)) {
734 struct ds match, actions;
737 ds_put_format(&match, "eth.dst == %s", op->nb->macs[i]);
740 ds_put_cstr(&actions, "outport = ");
741 json_string_escape(op->nb->name, &actions);
742 ds_put_cstr(&actions, "; output;");
743 ovn_lflow_add(&lflows, op->od, P_IN, 1, 50,
744 ds_cstr(&match), ds_cstr(&actions));
745 ds_destroy(&actions);
747 } else if (!strcmp(op->nb->macs[i], "unknown")) {
748 ovn_multicast_add(&mcgroups, &mc_unknown, op);
749 op->od->has_unknown = true;
751 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
753 VLOG_INFO_RL(&rl, "%s: invalid syntax '%s' in macs column",
754 op->nb->name, op->nb->macs[i]);
759 /* Ingress table 1: Destination lookup for unknown MACs (priority 0). */
760 HMAP_FOR_EACH (od, key_node, datapaths) {
761 if (od->has_unknown) {
762 ovn_lflow_add(&lflows, od, P_IN, 1, 0, "1",
763 "outport = \""MC_UNKNOWN"\"; output;");
767 /* Egress table 0: ACLs (any priority). */
768 HMAP_FOR_EACH (od, key_node, datapaths) {
769 for (size_t i = 0; i < od->nb->n_acls; i++) {
770 const struct nbrec_acl *acl = od->nb->acls[i];
773 action = (!strcmp(acl->action, "allow") ||
774 !strcmp(acl->action, "allow-related"))
776 ovn_lflow_add(&lflows, od, P_OUT, 0, acl->priority, acl->match,
780 HMAP_FOR_EACH (od, key_node, datapaths) {
781 ovn_lflow_add(&lflows, od, P_OUT, 0, 0, "1", "next;");
784 /* Egress table 1: Egress port security multicast/broadcast (priority
786 HMAP_FOR_EACH (od, key_node, datapaths) {
787 ovn_lflow_add(&lflows, od, P_OUT, 1, 100, "eth.dst[40]", "output;");
790 /* Egress table 1: Egress port security (priority 50). */
791 HMAP_FOR_EACH (op, key_node, ports) {
795 ds_put_cstr(&match, "outport == ");
796 json_string_escape(op->key, &match);
797 build_port_security("eth.dst",
798 op->nb->port_security, op->nb->n_port_security,
801 ovn_lflow_add(&lflows, op->od, P_OUT, 1, 50, ds_cstr(&match),
802 lport_is_enabled(op->nb) ? "output;" : "drop;");
807 /* Push changes to the Logical_Flow table to database. */
808 const struct sbrec_logical_flow *sbflow, *next_sbflow;
809 SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow, next_sbflow, ctx->ovnsb_idl) {
810 struct ovn_datapath *od
811 = ovn_datapath_from_sbrec(datapaths, sbflow->logical_datapath);
813 sbrec_logical_flow_delete(sbflow);
817 struct ovn_lflow *lflow = ovn_lflow_find(
818 &lflows, od, (!strcmp(sbflow->pipeline, "ingress") ? P_IN : P_OUT),
819 sbflow->table_id, sbflow->priority,
820 sbflow->match, sbflow->actions);
822 ovn_lflow_destroy(&lflows, lflow);
824 sbrec_logical_flow_delete(sbflow);
827 struct ovn_lflow *lflow, *next_lflow;
828 HMAP_FOR_EACH_SAFE (lflow, next_lflow, hmap_node, &lflows) {
829 sbflow = sbrec_logical_flow_insert(ctx->ovnsb_txn);
830 sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb);
831 sbrec_logical_flow_set_pipeline(
832 sbflow, lflow->pipeline == P_IN ? "ingress" : "egress");
833 sbrec_logical_flow_set_table_id(sbflow, lflow->table_id);
834 sbrec_logical_flow_set_priority(sbflow, lflow->priority);
835 sbrec_logical_flow_set_match(sbflow, lflow->match);
836 sbrec_logical_flow_set_actions(sbflow, lflow->actions);
837 ovn_lflow_destroy(&lflows, lflow);
839 hmap_destroy(&lflows);
841 /* Push changes to the Multicast_Group table to database. */
842 const struct sbrec_multicast_group *sbmc, *next_sbmc;
843 SBREC_MULTICAST_GROUP_FOR_EACH_SAFE (sbmc, next_sbmc, ctx->ovnsb_idl) {
844 struct ovn_datapath *od = ovn_datapath_from_sbrec(datapaths,
847 sbrec_multicast_group_delete(sbmc);
851 struct multicast_group group = { .name = sbmc->name,
852 .key = sbmc->tunnel_key };
853 struct ovn_multicast *mc = ovn_multicast_find(&mcgroups, od, &group);
855 ovn_multicast_update_sbrec(mc, sbmc);
856 ovn_multicast_destroy(&mcgroups, mc);
858 sbrec_multicast_group_delete(sbmc);
861 struct ovn_multicast *mc, *next_mc;
862 HMAP_FOR_EACH_SAFE (mc, next_mc, hmap_node, &mcgroups) {
863 sbmc = sbrec_multicast_group_insert(ctx->ovnsb_txn);
864 sbrec_multicast_group_set_datapath(sbmc, mc->datapath->sb);
865 sbrec_multicast_group_set_name(sbmc, mc->group->name);
866 sbrec_multicast_group_set_tunnel_key(sbmc, mc->group->key);
867 ovn_multicast_update_sbrec(mc, sbmc);
868 ovn_multicast_destroy(&mcgroups, mc);
870 hmap_destroy(&mcgroups);
874 ovnnb_db_changed(struct northd_context *ctx)
876 VLOG_DBG("ovn-nb db contents have changed.");
878 struct hmap datapaths, ports;
879 build_datapaths(ctx, &datapaths);
880 build_ports(ctx, &datapaths, &ports);
881 build_lflows(ctx, &datapaths, &ports);
883 struct ovn_datapath *dp, *next_dp;
884 HMAP_FOR_EACH_SAFE (dp, next_dp, key_node, &datapaths) {
885 ovn_datapath_destroy(&datapaths, dp);
887 hmap_destroy(&datapaths);
889 struct ovn_port *port, *next_port;
890 HMAP_FOR_EACH_SAFE (port, next_port, key_node, &ports) {
891 ovn_port_destroy(&ports, port);
893 hmap_destroy(&ports);
897 * The only change we get notified about is if the 'chassis' column of the
898 * 'Port_Binding' table changes. When this column is not empty, it means we
899 * need to set the corresponding logical port as 'up' in the northbound DB.
902 ovnsb_db_changed(struct northd_context *ctx)
904 struct hmap lports_hmap;
905 const struct sbrec_port_binding *sb;
906 const struct nbrec_logical_port *nb;
908 struct lport_hash_node {
909 struct hmap_node node;
910 const struct nbrec_logical_port *nb;
911 } *hash_node, *hash_node_next;
913 VLOG_DBG("Recalculating port up states for ovn-nb db.");
915 hmap_init(&lports_hmap);
917 NBREC_LOGICAL_PORT_FOR_EACH(nb, ctx->ovnnb_idl) {
918 hash_node = xzalloc(sizeof *hash_node);
920 hmap_insert(&lports_hmap, &hash_node->node, hash_string(nb->name, 0));
923 SBREC_PORT_BINDING_FOR_EACH(sb, ctx->ovnsb_idl) {
925 HMAP_FOR_EACH_WITH_HASH(hash_node, node,
926 hash_string(sb->logical_port, 0),
928 if (!strcmp(sb->logical_port, hash_node->nb->name)) {
935 /* The logical port doesn't exist for this port binding. This can
936 * happen under normal circumstances when ovn-northd hasn't gotten
937 * around to pruning the Port_Binding yet. */
941 if (sb->chassis && (!nb->up || !*nb->up)) {
943 nbrec_logical_port_set_up(nb, &up, 1);
944 } else if (!sb->chassis && (!nb->up || *nb->up)) {
946 nbrec_logical_port_set_up(nb, &up, 1);
950 HMAP_FOR_EACH_SAFE(hash_node, hash_node_next, node, &lports_hmap) {
951 hmap_remove(&lports_hmap, &hash_node->node);
954 hmap_destroy(&lports_hmap);
962 def = xasprintf("unix:%s/db.sock", ovs_rundir());
968 parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
974 static const struct option long_options[] = {
975 {"ovnsb-db", required_argument, NULL, 'd'},
976 {"ovnnb-db", required_argument, NULL, 'D'},
977 {"help", no_argument, NULL, 'h'},
978 {"options", no_argument, NULL, 'o'},
979 {"version", no_argument, NULL, 'V'},
982 STREAM_SSL_LONG_OPTIONS,
985 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
990 c = getopt_long(argc, argv, short_options, long_options, NULL);
996 DAEMON_OPTION_HANDLERS;
997 VLOG_OPTION_HANDLERS;
998 STREAM_SSL_OPTION_HANDLERS;
1013 ovs_cmdl_print_options(long_options);
1017 ovs_print_version(0, 0);
1026 ovnsb_db = default_db();
1030 ovnnb_db = default_db();
1033 free(short_options);
1037 add_column_noalert(struct ovsdb_idl *idl,
1038 const struct ovsdb_idl_column *column)
1040 ovsdb_idl_add_column(idl, column);
1041 ovsdb_idl_omit_alert(idl, column);
1045 main(int argc, char *argv[])
1047 extern struct vlog_module VLM_reconnect;
1048 struct ovsdb_idl *ovnnb_idl, *ovnsb_idl;
1049 unsigned int ovnnb_seqno, ovn_seqno;
1050 int res = EXIT_SUCCESS;
1051 struct northd_context ctx = {
1054 bool ovnnb_changes_pending = false;
1055 bool ovn_changes_pending = false;
1056 struct unixctl_server *unixctl;
1060 fatal_ignore_sigpipe();
1061 set_program_name(argv[0]);
1062 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
1063 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
1064 parse_options(argc, argv);
1068 retval = unixctl_server_create(NULL, &unixctl);
1072 unixctl_command_register("exit", "", 0, 0, ovn_northd_exit, &exiting);
1074 daemonize_complete();
1079 /* We want to detect all changes to the ovn-nb db. */
1080 ctx.ovnnb_idl = ovnnb_idl = ovsdb_idl_create(ovnnb_db,
1081 &nbrec_idl_class, true, true);
1083 ctx.ovnsb_idl = ovnsb_idl = ovsdb_idl_create(ovnsb_db,
1084 &sbrec_idl_class, false, true);
1086 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_logical_flow);
1087 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_logical_datapath);
1088 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_pipeline);
1089 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_table_id);
1090 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_priority);
1091 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_match);
1092 add_column_noalert(ovnsb_idl, &sbrec_logical_flow_col_actions);
1094 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_multicast_group);
1095 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_datapath);
1096 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_tunnel_key);
1097 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_name);
1098 add_column_noalert(ovnsb_idl, &sbrec_multicast_group_col_ports);
1100 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_datapath_binding);
1101 add_column_noalert(ovnsb_idl, &sbrec_datapath_binding_col_tunnel_key);
1102 add_column_noalert(ovnsb_idl, &sbrec_datapath_binding_col_external_ids);
1104 ovsdb_idl_add_table(ovnsb_idl, &sbrec_table_port_binding);
1105 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_datapath);
1106 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_logical_port);
1107 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_tunnel_key);
1108 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_parent_port);
1109 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_tag);
1110 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_type);
1111 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_options);
1112 add_column_noalert(ovnsb_idl, &sbrec_port_binding_col_mac);
1113 ovsdb_idl_add_column(ovnsb_idl, &sbrec_port_binding_col_chassis);
1116 * The loop here just runs the IDL in a loop waiting for the seqno to
1117 * change, which indicates that the contents of the db have changed.
1119 * If the contents of the ovn-nb db change, the mappings to the ovn-sb
1120 * db must be recalculated.
1122 * If the contents of the ovn-sb db change, it means the 'up' state of
1123 * a port may have changed, as that's the only type of change ovn-northd is
1127 ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl);
1128 ovn_seqno = ovsdb_idl_get_seqno(ovnsb_idl);
1131 ovsdb_idl_run(ovnnb_idl);
1132 ovsdb_idl_run(ovnsb_idl);
1133 unixctl_server_run(unixctl);
1135 if (!ovsdb_idl_is_alive(ovnnb_idl)) {
1136 int retval = ovsdb_idl_get_last_error(ovnnb_idl);
1137 VLOG_ERR("%s: database connection failed (%s)",
1138 ovnnb_db, ovs_retval_to_string(retval));
1143 if (!ovsdb_idl_is_alive(ovnsb_idl)) {
1144 int retval = ovsdb_idl_get_last_error(ovnsb_idl);
1145 VLOG_ERR("%s: database connection failed (%s)",
1146 ovnsb_db, ovs_retval_to_string(retval));
1151 if (ovnnb_seqno != ovsdb_idl_get_seqno(ovnnb_idl)) {
1152 ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl);
1153 ovnnb_changes_pending = true;
1156 if (ovn_seqno != ovsdb_idl_get_seqno(ovnsb_idl)) {
1157 ovn_seqno = ovsdb_idl_get_seqno(ovnsb_idl);
1158 ovn_changes_pending = true;
1162 * If there are any pending changes, we delay recalculating the
1163 * necessary updates until after an existing transaction finishes.
1164 * This avoids the possibility of rapid updates causing ovn-northd to
1165 * never be able to successfully make the corresponding updates to the
1166 * other db. Instead, pending changes are batched up until the next
1167 * time we get a chance to calculate the new state and apply it.
1170 if (ovnnb_changes_pending && !ctx.ovnsb_txn) {
1172 * The OVN-nb db contents have changed, so create a transaction for
1173 * updating the OVN-sb DB.
1175 ctx.ovnsb_txn = ovsdb_idl_txn_create(ctx.ovnsb_idl);
1176 ovsdb_idl_txn_add_comment(ctx.ovnsb_txn,
1177 "ovn-northd: northbound db changed");
1178 ovnnb_db_changed(&ctx);
1179 ovnnb_changes_pending = false;
1182 if (ovn_changes_pending && !ctx.ovnnb_txn) {
1184 * The OVN-sb db contents have changed, so create a transaction for
1185 * updating the northbound DB.
1187 ctx.ovnnb_txn = ovsdb_idl_txn_create(ctx.ovnnb_idl);
1188 ovsdb_idl_txn_add_comment(ctx.ovnnb_txn,
1189 "ovn-northd: southbound db changed");
1190 ovnsb_db_changed(&ctx);
1191 ovn_changes_pending = false;
1194 if (ctx.ovnnb_txn) {
1195 enum ovsdb_idl_txn_status txn_status;
1196 txn_status = ovsdb_idl_txn_commit(ctx.ovnnb_txn);
1197 switch (txn_status) {
1198 case TXN_UNCOMMITTED:
1199 case TXN_INCOMPLETE:
1200 /* Come back around and try to commit this transaction again */
1204 case TXN_NOT_LOCKED:
1206 /* Something went wrong, so try creating a new transaction. */
1207 ovn_changes_pending = true;
1210 ovsdb_idl_txn_destroy(ctx.ovnnb_txn);
1211 ctx.ovnnb_txn = NULL;
1215 if (ctx.ovnsb_txn) {
1216 enum ovsdb_idl_txn_status txn_status;
1217 txn_status = ovsdb_idl_txn_commit(ctx.ovnsb_txn);
1218 switch (txn_status) {
1219 case TXN_UNCOMMITTED:
1220 case TXN_INCOMPLETE:
1221 /* Come back around and try to commit this transaction again */
1225 case TXN_NOT_LOCKED:
1227 /* Something went wrong, so try creating a new transaction. */
1228 ovnnb_changes_pending = true;
1231 ovsdb_idl_txn_destroy(ctx.ovnsb_txn);
1232 ctx.ovnsb_txn = NULL;
1236 if (ovnnb_seqno == ovsdb_idl_get_seqno(ovnnb_idl) &&
1237 ovn_seqno == ovsdb_idl_get_seqno(ovnsb_idl)) {
1238 ovsdb_idl_wait(ovnnb_idl);
1239 ovsdb_idl_wait(ovnsb_idl);
1240 if (ctx.ovnnb_txn) {
1241 ovsdb_idl_txn_wait(ctx.ovnnb_txn);
1243 if (ctx.ovnsb_txn) {
1244 ovsdb_idl_txn_wait(ctx.ovnsb_txn);
1246 unixctl_server_wait(unixctl);
1248 poll_immediate_wake();
1254 unixctl_server_destroy(unixctl);
1255 ovsdb_idl_destroy(ovnsb_idl);
1256 ovsdb_idl_destroy(ovnnb_idl);
1262 ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
1263 const char *argv[] OVS_UNUSED, void *exiting_)
1265 bool *exiting = exiting_;
1268 unixctl_command_reply(conn, NULL);