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);
58 /* Ingress pipeline stages.
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) \
63 INGRESS_STAGE(ACL, acl) \
64 INGRESS_STAGE(L2_LKUP, l2_lkup)
67 #define INGRESS_STAGE(NAME, STR) S_IN_##NAME,
73 /* Egress pipeline stages.
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)
81 #define EGRESS_STAGE(NAME, STR) S_OUT_##NAME,
91 %s: OVN northbound management daemon\n\
92 usage: %s [OPTIONS]\n\
95 --ovnnb-db=DATABASE connect to ovn-nb database at DATABASE\n\
97 --ovnsb-db=DATABASE connect to ovn-sb database at DATABASE\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());
105 stream_usage("database", true, true, false);
109 struct hmap_node hmap_node
;
114 destroy_tnlids(struct hmap
*tnlids
)
116 struct tnlid_node
*node
, *next
;
117 HMAP_FOR_EACH_SAFE (node
, next
, hmap_node
, tnlids
) {
118 hmap_remove(tnlids
, &node
->hmap_node
);
121 hmap_destroy(tnlids
);
125 add_tnlid(struct hmap
*set
, uint32_t tnlid
)
127 struct tnlid_node
*node
= xmalloc(sizeof *node
);
128 hmap_insert(set
, &node
->hmap_node
, hash_int(tnlid
, 0));
133 tnlid_in_use(const struct hmap
*set
, uint32_t tnlid
)
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
) {
145 allocate_tnlid(struct hmap
*set
, const char *name
, uint32_t max
,
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
);
157 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
158 VLOG_WARN_RL(&rl
, "all %s tunnel ids exhausted", name
);
162 /* The 'key' comes from nb->header_.uuid or sb->external_ids:logical-switch. */
163 struct ovn_datapath
{
164 struct hmap_node key_node
; /* Index on 'key'. */
165 struct uuid key
; /* nb->header_.uuid. */
167 const struct nbrec_logical_switch
*nb
; /* May be NULL. */
168 const struct sbrec_datapath_binding
*sb
; /* May be NULL. */
170 struct ovs_list list
; /* In list of similar records. */
172 struct hmap port_tnlids
;
173 uint32_t port_key_hint
;
178 static struct ovn_datapath
*
179 ovn_datapath_create(struct hmap
*datapaths
, const struct uuid
*key
,
180 const struct nbrec_logical_switch
*nb
,
181 const struct sbrec_datapath_binding
*sb
)
183 struct ovn_datapath
*od
= xzalloc(sizeof *od
);
187 hmap_init(&od
->port_tnlids
);
188 od
->port_key_hint
= 0;
189 hmap_insert(datapaths
, &od
->key_node
, uuid_hash(&od
->key
));
194 ovn_datapath_destroy(struct hmap
*datapaths
, struct ovn_datapath
*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
200 hmap_remove(datapaths
, &od
->key_node
);
201 destroy_tnlids(&od
->port_tnlids
);
206 static struct ovn_datapath
*
207 ovn_datapath_find(struct hmap
*datapaths
, const struct uuid
*uuid
)
209 struct ovn_datapath
*od
;
211 HMAP_FOR_EACH_WITH_HASH (od
, key_node
, uuid_hash(uuid
), datapaths
) {
212 if (uuid_equals(uuid
, &od
->key
)) {
219 static struct ovn_datapath
*
220 ovn_datapath_from_sbrec(struct hmap
*datapaths
,
221 const struct sbrec_datapath_binding
*sb
)
225 if (!smap_get_uuid(&sb
->external_ids
, "logical-switch", &key
)) {
228 return ovn_datapath_find(datapaths
, &key
);
232 join_datapaths(struct northd_context
*ctx
, struct hmap
*datapaths
,
233 struct ovs_list
*sb_only
, struct ovs_list
*nb_only
,
234 struct ovs_list
*both
)
236 hmap_init(datapaths
);
241 const struct sbrec_datapath_binding
*sb
, *sb_next
;
242 SBREC_DATAPATH_BINDING_FOR_EACH_SAFE (sb
, sb_next
, ctx
->ovnsb_idl
) {
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
);
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
);
262 struct ovn_datapath
*od
= ovn_datapath_create(datapaths
, &key
,
264 list_push_back(sb_only
, &od
->list
);
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
,
273 list_remove(&od
->list
);
274 list_push_back(both
, &od
->list
);
276 od
= ovn_datapath_create(datapaths
, &nb
->header_
.uuid
, nb
, NULL
);
277 list_push_back(nb_only
, &od
->list
);
283 ovn_datapath_allocate_key(struct hmap
*dp_tnlids
)
285 static uint32_t hint
;
286 return allocate_tnlid(dp_tnlids
, "datapath", (1u << 24) - 1, &hint
);
290 build_datapaths(struct northd_context
*ctx
, struct hmap
*datapaths
)
292 struct ovs_list sb_only
, nb_only
, both
;
294 join_datapaths(ctx
, datapaths
, &sb_only
, &nb_only
, &both
);
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
);
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
);
311 od
->sb
= sbrec_datapath_binding_insert(ctx
->ovnsb_txn
);
313 char uuid_s
[UUID_LEN
+ 1];
314 sprintf(uuid_s
, UUID_FMT
, UUID_ARGS(&od
->nb
->header_
.uuid
));
315 const struct smap id
= SMAP_CONST1(&id
, "logical-switch", uuid_s
);
316 sbrec_datapath_binding_set_external_ids(od
->sb
, &id
);
318 sbrec_datapath_binding_set_tunnel_key(od
->sb
, tunnel_key
);
320 destroy_tnlids(&dp_tnlids
);
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
);
333 struct hmap_node key_node
; /* Index on 'key'. */
334 const char *key
; /* nb->name and sb->logical_port */
336 const struct nbrec_logical_port
*nb
; /* May be NULL. */
337 const struct sbrec_port_binding
*sb
; /* May be NULL. */
339 struct ovn_datapath
*od
;
341 struct ovs_list list
; /* In list of similar records. */
344 static struct ovn_port
*
345 ovn_port_create(struct hmap
*ports
, const char *key
,
346 const struct nbrec_logical_port
*nb
,
347 const struct sbrec_port_binding
*sb
)
349 struct ovn_port
*op
= xzalloc(sizeof *op
);
353 hmap_insert(ports
, &op
->key_node
, hash_string(op
->key
, 0));
358 ovn_port_destroy(struct hmap
*ports
, struct ovn_port
*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
364 hmap_remove(ports
, &port
->key_node
);
369 static struct ovn_port
*
370 ovn_port_find(struct hmap
*ports
, const char *name
)
374 HMAP_FOR_EACH_WITH_HASH (op
, key_node
, hash_string(name
, 0), ports
) {
375 if (!strcmp(op
->key
, name
)) {
383 ovn_port_allocate_key(struct ovn_datapath
*od
)
385 return allocate_tnlid(&od
->port_tnlids
, "port",
386 (1u << 15) - 1, &od
->port_key_hint
);
390 join_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
)
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
,
404 list_push_back(sb_only
, &op
->list
);
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
);
414 list_remove(&op
->list
);
415 list_push_back(both
, &op
->list
);
417 op
= ovn_port_create(ports
, nb
->name
, nb
, NULL
);
418 list_push_back(nb_only
, &op
->list
);
426 ovn_port_update_sbrec(const struct ovn_port
*op
)
428 sbrec_port_binding_set_type(op
->sb
, op
->nb
->type
);
429 sbrec_port_binding_set_options(op
->sb
, &op
->nb
->options
);
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
,
438 build_ports(struct northd_context
*ctx
, struct hmap
*datapaths
,
441 struct ovs_list sb_only
, nb_only
, both
;
443 join_logical_ports(ctx
, datapaths
, ports
, &sb_only
, &nb_only
, &both
);
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
);
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
;
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
);
464 op
->sb
= sbrec_port_binding_insert(ctx
->ovnsb_txn
);
465 ovn_port_update_sbrec(op
);
467 sbrec_port_binding_set_logical_port(op
->sb
, op
->key
);
468 sbrec_port_binding_set_tunnel_key(op
->sb
, tunnel_key
);
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
);
479 #define OVN_MIN_MULTICAST 32768
480 #define OVN_MAX_MULTICAST 65535
482 struct multicast_group
{
484 uint16_t key
; /* OVN_MIN_MULTICAST...OVN_MAX_MULTICAST. */
487 #define MC_FLOOD "_MC_flood"
488 static const struct multicast_group mc_flood
= { MC_FLOOD
, 65535 };
490 #define MC_UNKNOWN "_MC_unknown"
491 static const struct multicast_group mc_unknown
= { MC_UNKNOWN
, 65534 };
494 multicast_group_equal(const struct multicast_group
*a
,
495 const struct multicast_group
*b
)
497 return !strcmp(a
->name
, b
->name
) && a
->key
== b
->key
;
500 /* Multicast group entry. */
501 struct ovn_multicast
{
502 struct hmap_node hmap_node
; /* Index on 'datapath' and 'key'. */
503 struct ovn_datapath
*datapath
;
504 const struct multicast_group
*group
;
506 struct ovn_port
**ports
;
507 size_t n_ports
, allocated_ports
;
511 ovn_multicast_hash(const struct ovn_datapath
*datapath
,
512 const struct multicast_group
*group
)
514 return hash_pointer(datapath
, group
->key
);
517 static struct ovn_multicast
*
518 ovn_multicast_find(struct hmap
*mcgroups
, struct ovn_datapath
*datapath
,
519 const struct multicast_group
*group
)
521 struct ovn_multicast
*mc
;
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
)) {
534 ovn_multicast_add(struct hmap
*mcgroups
, const struct multicast_group
*group
,
535 struct ovn_port
*port
)
537 struct ovn_datapath
*od
= port
->od
;
538 struct ovn_multicast
*mc
= ovn_multicast_find(mcgroups
, od
, group
);
540 mc
= xmalloc(sizeof *mc
);
541 hmap_insert(mcgroups
, &mc
->hmap_node
, ovn_multicast_hash(od
, group
));
545 mc
->allocated_ports
= 4;
546 mc
->ports
= xmalloc(mc
->allocated_ports
* sizeof *mc
->ports
);
548 if (mc
->n_ports
>= mc
->allocated_ports
) {
549 mc
->ports
= x2nrealloc(mc
->ports
, &mc
->allocated_ports
,
552 mc
->ports
[mc
->n_ports
++] = port
;
556 ovn_multicast_destroy(struct hmap
*mcgroups
, struct ovn_multicast
*mc
)
559 hmap_remove(mcgroups
, &mc
->hmap_node
);
566 ovn_multicast_update_sbrec(const struct ovn_multicast
*mc
,
567 const struct sbrec_multicast_group
*sb
)
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
);
573 sbrec_multicast_group_set_ports(sb
, ports
, mc
->n_ports
);
577 /* Logical flow generation.
579 * This code generates the Logical_Flow table in the southbound database, as a
580 * function of most of the northbound database.
584 struct hmap_node hmap_node
;
586 struct ovn_datapath
*od
;
587 enum ovn_pipeline
{ P_IN
, P_OUT
} pipeline
;
595 ovn_lflow_hash(const struct ovn_lflow
*lflow
)
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
);
604 ovn_lflow_equal(const struct ovn_lflow
*a
, const struct ovn_lflow
*b
)
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
));
615 ovn_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
)
620 lflow
->pipeline
= pipeline
;
621 lflow
->table_id
= table_id
;
622 lflow
->priority
= priority
;
623 lflow
->match
= match
;
624 lflow
->actions
= actions
;
628 ingress_stage_to_str(int stage
) {
630 #define INGRESS_STAGE(NAME, STR) case S_IN_##NAME: return #STR;
633 default: return "<unknown>";
638 egress_stage_to_str(int stage
) {
640 #define EGRESS_STAGE(NAME, STR) case S_OUT_##NAME: return #STR;
643 default: return "<unknown>";
647 /* Adds a row with the specified contents to the Logical_Flow table. */
649 ovn_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
)
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
));
659 static struct ovn_lflow
*
660 ovn_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
)
664 struct ovn_lflow target
;
665 ovn_lflow_init(&target
, od
, pipeline
, table_id
, priority
,
666 CONST_CAST(char *, match
), CONST_CAST(char *, actions
));
668 struct ovn_lflow
*lflow
;
669 HMAP_FOR_EACH_WITH_HASH (lflow
, hmap_node
, ovn_lflow_hash(&target
),
671 if (ovn_lflow_equal(lflow
, &target
)) {
679 ovn_lflow_destroy(struct hmap
*lflows
, struct ovn_lflow
*lflow
)
682 hmap_remove(lflows
, &lflow
->hmap_node
);
684 free(lflow
->actions
);
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
692 * from an OVN_NB Logical_Port row. */
694 build_port_security(const char *eth_addr_field
,
695 char **port_security
, size_t n_port_security
,
698 size_t base_len
= match
->length
;
699 ds_put_format(match
, " && %s == {", eth_addr_field
);
702 for (size_t i
= 0; i
< n_port_security
; i
++) {
705 if (eth_addr_from_string(port_security
[i
], &ea
)) {
706 ds_put_format(match
, ETH_ADDR_FMT
, ETH_ADDR_ARGS(ea
));
707 ds_put_char(match
, ' ');
711 ds_chomp(match
, ' ');
712 ds_put_cstr(match
, "}");
715 match
->length
= base_len
;
720 lport_is_enabled(const struct nbrec_logical_port
*lport
)
722 return !lport
->enabled
|| *lport
->enabled
;
725 /* Updates the Logical_Flow and Multicast_Group tables in the OVN_SB database,
726 * constructing their contents based on the OVN_NB database. */
728 build_lflows(struct northd_context
*ctx
, struct hmap
*datapaths
,
731 struct hmap lflows
= HMAP_INITIALIZER(&lflows
);
732 struct hmap mcgroups
= HMAP_INITIALIZER(&mcgroups
);
734 /* Ingress table 0: Admission control framework (priorities 0 and 100). */
735 struct ovn_datapath
*od
;
736 HMAP_FOR_EACH (od
, key_node
, datapaths
) {
737 /* Logical VLANs not supported. */
738 ovn_lflow_add(&lflows
, od
, P_IN
, S_IN_PORT_SEC
, 100, "vlan.present",
741 /* Broadcast/multicast source address is invalid. */
742 ovn_lflow_add(&lflows
, od
, P_IN
, S_IN_PORT_SEC
, 100, "eth.src[40]",
745 /* Port security flows have priority 50 (see below) and will continue
746 * to the next table if packet source is acceptable. */
748 /* Otherwise drop the packet. */
749 ovn_lflow_add(&lflows
, od
, P_IN
, S_IN_PORT_SEC
, 0, "1", "drop;");
752 /* Ingress table 0: Ingress port security (priority 50). */
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
,
761 ovn_lflow_add(&lflows
, op
->od
, P_IN
, S_IN_PORT_SEC
, 50, ds_cstr(&match
),
762 lport_is_enabled(op
->nb
) ? "next;" : "drop;");
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
];
772 if (strcmp(acl
->direction
, "from-lport")) {
776 action
= (!strcmp(acl
->action
, "allow") ||
777 !strcmp(acl
->action
, "allow-related"))
779 ovn_lflow_add(&lflows
, od
, P_IN
, S_IN_ACL
, acl
->priority
,
783 HMAP_FOR_EACH (od
, key_node
, datapaths
) {
784 ovn_lflow_add(&lflows
, od
, P_IN
, S_IN_ACL
, 0, "1", "next;");
787 /* Ingress table 2: Destination lookup, broadcast and multicast handling
789 HMAP_FOR_EACH (op
, key_node
, ports
) {
790 if (lport_is_enabled(op
->nb
)) {
791 ovn_multicast_add(&mcgroups
, &mc_flood
, op
);
794 HMAP_FOR_EACH (od
, key_node
, datapaths
) {
795 ovn_lflow_add(&lflows
, od
, P_IN
, S_IN_L2_LKUP
, 100, "eth.dst[40]",
796 "outport = \""MC_FLOOD
"\"; output;");
799 /* Ingress table 2: Destination lookup, unicast handling (priority 50), */
800 HMAP_FOR_EACH (op
, key_node
, ports
) {
801 for (size_t i
= 0; i
< op
->nb
->n_macs
; i
++) {
804 if (eth_addr_from_string(op
->nb
->macs
[i
], &mac
)) {
805 struct ds match
, actions
;
808 ds_put_format(&match
, "eth.dst == %s", op
->nb
->macs
[i
]);
811 ds_put_cstr(&actions
, "outport = ");
812 json_string_escape(op
->nb
->name
, &actions
);
813 ds_put_cstr(&actions
, "; output;");
814 ovn_lflow_add(&lflows
, op
->od
, P_IN
, S_IN_L2_LKUP
, 50,
815 ds_cstr(&match
), ds_cstr(&actions
));
816 ds_destroy(&actions
);
818 } else if (!strcmp(op
->nb
->macs
[i
], "unknown")) {
819 ovn_multicast_add(&mcgroups
, &mc_unknown
, op
);
820 op
->od
->has_unknown
= true;
822 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 1);
824 VLOG_INFO_RL(&rl
, "%s: invalid syntax '%s' in macs column",
825 op
->nb
->name
, op
->nb
->macs
[i
]);
830 /* Ingress table 2: Destination lookup for unknown MACs (priority 0). */
831 HMAP_FOR_EACH (od
, key_node
, datapaths
) {
832 if (od
->has_unknown
) {
833 ovn_lflow_add(&lflows
, od
, P_IN
, S_IN_L2_LKUP
, 0, "1",
834 "outport = \""MC_UNKNOWN
"\"; output;");
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
];
844 if (strcmp(acl
->direction
, "to-lport")) {
848 action
= (!strcmp(acl
->action
, "allow") ||
849 !strcmp(acl
->action
, "allow-related"))
851 ovn_lflow_add(&lflows
, od
, P_OUT
, S_OUT_ACL
, acl
->priority
,
855 HMAP_FOR_EACH (od
, key_node
, datapaths
) {
856 ovn_lflow_add(&lflows
, od
, P_OUT
, S_OUT_ACL
, 0, "1", "next;");
859 /* Egress table 1: Egress port security multicast/broadcast (priority
861 HMAP_FOR_EACH (od
, key_node
, datapaths
) {
862 ovn_lflow_add(&lflows
, od
, P_OUT
, S_OUT_PORT_SEC
, 100, "eth.dst[40]",
866 /* Egress table 1: Egress port security (priority 50). */
867 HMAP_FOR_EACH (op
, key_node
, ports
) {
871 ds_put_cstr(&match
, "outport == ");
872 json_string_escape(op
->key
, &match
);
873 build_port_security("eth.dst",
874 op
->nb
->port_security
, op
->nb
->n_port_security
,
877 ovn_lflow_add(&lflows
, op
->od
, P_OUT
, S_OUT_PORT_SEC
, 50,
879 lport_is_enabled(op
->nb
) ? "output;" : "drop;");
884 /* Push changes to the Logical_Flow table to database. */
885 const struct sbrec_logical_flow
*sbflow
, *next_sbflow
;
886 SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow
, next_sbflow
, ctx
->ovnsb_idl
) {
887 struct ovn_datapath
*od
888 = ovn_datapath_from_sbrec(datapaths
, sbflow
->logical_datapath
);
890 sbrec_logical_flow_delete(sbflow
);
894 struct ovn_lflow
*lflow
= ovn_lflow_find(
895 &lflows
, od
, (!strcmp(sbflow
->pipeline
, "ingress") ? P_IN
: P_OUT
),
896 sbflow
->table_id
, sbflow
->priority
,
897 sbflow
->match
, sbflow
->actions
);
899 ovn_lflow_destroy(&lflows
, lflow
);
901 sbrec_logical_flow_delete(sbflow
);
904 struct ovn_lflow
*lflow
, *next_lflow
;
905 HMAP_FOR_EACH_SAFE (lflow
, next_lflow
, hmap_node
, &lflows
) {
906 sbflow
= sbrec_logical_flow_insert(ctx
->ovnsb_txn
);
907 sbrec_logical_flow_set_logical_datapath(sbflow
, lflow
->od
->sb
);
908 sbrec_logical_flow_set_pipeline(
909 sbflow
, lflow
->pipeline
== P_IN
? "ingress" : "egress");
910 sbrec_logical_flow_set_table_id(sbflow
, lflow
->table_id
);
911 sbrec_logical_flow_set_priority(sbflow
, lflow
->priority
);
912 sbrec_logical_flow_set_match(sbflow
, lflow
->match
);
913 sbrec_logical_flow_set_actions(sbflow
, lflow
->actions
);
915 const struct smap ids
= SMAP_CONST1(
917 (lflow
->pipeline
== P_IN
918 ? ingress_stage_to_str(lflow
->table_id
)
919 : egress_stage_to_str(lflow
->table_id
)));
920 sbrec_logical_flow_set_external_ids(sbflow
, &ids
);
922 ovn_lflow_destroy(&lflows
, lflow
);
924 hmap_destroy(&lflows
);
926 /* Push changes to the Multicast_Group table to database. */
927 const struct sbrec_multicast_group
*sbmc
, *next_sbmc
;
928 SBREC_MULTICAST_GROUP_FOR_EACH_SAFE (sbmc
, next_sbmc
, ctx
->ovnsb_idl
) {
929 struct ovn_datapath
*od
= ovn_datapath_from_sbrec(datapaths
,
932 sbrec_multicast_group_delete(sbmc
);
936 struct multicast_group group
= { .name
= sbmc
->name
,
937 .key
= sbmc
->tunnel_key
};
938 struct ovn_multicast
*mc
= ovn_multicast_find(&mcgroups
, od
, &group
);
940 ovn_multicast_update_sbrec(mc
, sbmc
);
941 ovn_multicast_destroy(&mcgroups
, mc
);
943 sbrec_multicast_group_delete(sbmc
);
946 struct ovn_multicast
*mc
, *next_mc
;
947 HMAP_FOR_EACH_SAFE (mc
, next_mc
, hmap_node
, &mcgroups
) {
948 sbmc
= sbrec_multicast_group_insert(ctx
->ovnsb_txn
);
949 sbrec_multicast_group_set_datapath(sbmc
, mc
->datapath
->sb
);
950 sbrec_multicast_group_set_name(sbmc
, mc
->group
->name
);
951 sbrec_multicast_group_set_tunnel_key(sbmc
, mc
->group
->key
);
952 ovn_multicast_update_sbrec(mc
, sbmc
);
953 ovn_multicast_destroy(&mcgroups
, mc
);
955 hmap_destroy(&mcgroups
);
959 ovnnb_db_changed(struct northd_context
*ctx
)
961 VLOG_DBG("ovn-nb db contents have changed.");
963 struct hmap datapaths
, ports
;
964 build_datapaths(ctx
, &datapaths
);
965 build_ports(ctx
, &datapaths
, &ports
);
966 build_lflows(ctx
, &datapaths
, &ports
);
968 struct ovn_datapath
*dp
, *next_dp
;
969 HMAP_FOR_EACH_SAFE (dp
, next_dp
, key_node
, &datapaths
) {
970 ovn_datapath_destroy(&datapaths
, dp
);
972 hmap_destroy(&datapaths
);
974 struct ovn_port
*port
, *next_port
;
975 HMAP_FOR_EACH_SAFE (port
, next_port
, key_node
, &ports
) {
976 ovn_port_destroy(&ports
, port
);
978 hmap_destroy(&ports
);
982 * The only change we get notified about is if the 'chassis' column of the
983 * 'Port_Binding' table changes. When this column is not empty, it means we
984 * need to set the corresponding logical port as 'up' in the northbound DB.
987 ovnsb_db_changed(struct northd_context
*ctx
)
989 struct hmap lports_hmap
;
990 const struct sbrec_port_binding
*sb
;
991 const struct nbrec_logical_port
*nb
;
993 struct lport_hash_node
{
994 struct hmap_node node
;
995 const struct nbrec_logical_port
*nb
;
996 } *hash_node
, *hash_node_next
;
998 VLOG_DBG("Recalculating port up states for ovn-nb db.");
1000 hmap_init(&lports_hmap
);
1002 NBREC_LOGICAL_PORT_FOR_EACH(nb
, ctx
->ovnnb_idl
) {
1003 hash_node
= xzalloc(sizeof *hash_node
);
1005 hmap_insert(&lports_hmap
, &hash_node
->node
, hash_string(nb
->name
, 0));
1008 SBREC_PORT_BINDING_FOR_EACH(sb
, ctx
->ovnsb_idl
) {
1010 HMAP_FOR_EACH_WITH_HASH(hash_node
, node
,
1011 hash_string(sb
->logical_port
, 0),
1013 if (!strcmp(sb
->logical_port
, hash_node
->nb
->name
)) {
1020 /* The logical port doesn't exist for this port binding. This can
1021 * happen under normal circumstances when ovn-northd hasn't gotten
1022 * around to pruning the Port_Binding yet. */
1026 if (sb
->chassis
&& (!nb
->up
|| !*nb
->up
)) {
1028 nbrec_logical_port_set_up(nb
, &up
, 1);
1029 } else if (!sb
->chassis
&& (!nb
->up
|| *nb
->up
)) {
1031 nbrec_logical_port_set_up(nb
, &up
, 1);
1035 HMAP_FOR_EACH_SAFE(hash_node
, hash_node_next
, node
, &lports_hmap
) {
1036 hmap_remove(&lports_hmap
, &hash_node
->node
);
1039 hmap_destroy(&lports_hmap
);
1043 static char *default_db_
;
1049 default_db_
= xasprintf("unix:%s/db.sock", ovs_rundir());
1055 parse_options(int argc OVS_UNUSED
, char *argv
[] OVS_UNUSED
)
1058 DAEMON_OPTION_ENUMS
,
1061 static const struct option long_options
[] = {
1062 {"ovnsb-db", required_argument
, NULL
, 'd'},
1063 {"ovnnb-db", required_argument
, NULL
, 'D'},
1064 {"help", no_argument
, NULL
, 'h'},
1065 {"options", no_argument
, NULL
, 'o'},
1066 {"version", no_argument
, NULL
, 'V'},
1067 DAEMON_LONG_OPTIONS
,
1069 STREAM_SSL_LONG_OPTIONS
,
1072 char *short_options
= ovs_cmdl_long_options_to_short_options(long_options
);
1077 c
= getopt_long(argc
, argv
, short_options
, long_options
, NULL
);
1083 DAEMON_OPTION_HANDLERS
;
1084 VLOG_OPTION_HANDLERS
;
1085 STREAM_SSL_OPTION_HANDLERS
;
1100 ovs_cmdl_print_options(long_options
);
1104 ovs_print_version(0, 0);
1113 ovnsb_db
= default_db();
1117 ovnnb_db
= default_db();
1120 free(short_options
);
1124 add_column_noalert(struct ovsdb_idl
*idl
,
1125 const struct ovsdb_idl_column
*column
)
1127 ovsdb_idl_add_column(idl
, column
);
1128 ovsdb_idl_omit_alert(idl
, column
);
1132 main(int argc
, char *argv
[])
1134 extern struct vlog_module VLM_reconnect
;
1135 struct ovsdb_idl
*ovnnb_idl
, *ovnsb_idl
;
1136 unsigned int ovnnb_seqno
, ovn_seqno
;
1137 int res
= EXIT_SUCCESS
;
1138 struct northd_context ctx
= {
1141 bool ovnnb_changes_pending
= false;
1142 bool ovn_changes_pending
= false;
1143 struct unixctl_server
*unixctl
;
1147 fatal_ignore_sigpipe();
1148 set_program_name(argv
[0]);
1149 service_start(&argc
, &argv
);
1150 vlog_set_levels(NULL
, VLF_CONSOLE
, VLL_WARN
);
1151 vlog_set_levels(&VLM_reconnect
, VLF_ANY_DESTINATION
, VLL_WARN
);
1152 parse_options(argc
, argv
);
1156 retval
= unixctl_server_create(NULL
, &unixctl
);
1160 unixctl_command_register("exit", "", 0, 0, ovn_northd_exit
, &exiting
);
1162 daemonize_complete();
1167 /* We want to detect all changes to the ovn-nb db. */
1168 ctx
.ovnnb_idl
= ovnnb_idl
= ovsdb_idl_create(ovnnb_db
,
1169 &nbrec_idl_class
, true, true);
1171 ctx
.ovnsb_idl
= ovnsb_idl
= ovsdb_idl_create(ovnsb_db
,
1172 &sbrec_idl_class
, false, true);
1174 ovsdb_idl_add_table(ovnsb_idl
, &sbrec_table_logical_flow
);
1175 add_column_noalert(ovnsb_idl
, &sbrec_logical_flow_col_logical_datapath
);
1176 add_column_noalert(ovnsb_idl
, &sbrec_logical_flow_col_pipeline
);
1177 add_column_noalert(ovnsb_idl
, &sbrec_logical_flow_col_table_id
);
1178 add_column_noalert(ovnsb_idl
, &sbrec_logical_flow_col_priority
);
1179 add_column_noalert(ovnsb_idl
, &sbrec_logical_flow_col_match
);
1180 add_column_noalert(ovnsb_idl
, &sbrec_logical_flow_col_actions
);
1182 ovsdb_idl_add_table(ovnsb_idl
, &sbrec_table_multicast_group
);
1183 add_column_noalert(ovnsb_idl
, &sbrec_multicast_group_col_datapath
);
1184 add_column_noalert(ovnsb_idl
, &sbrec_multicast_group_col_tunnel_key
);
1185 add_column_noalert(ovnsb_idl
, &sbrec_multicast_group_col_name
);
1186 add_column_noalert(ovnsb_idl
, &sbrec_multicast_group_col_ports
);
1188 ovsdb_idl_add_table(ovnsb_idl
, &sbrec_table_datapath_binding
);
1189 add_column_noalert(ovnsb_idl
, &sbrec_datapath_binding_col_tunnel_key
);
1190 add_column_noalert(ovnsb_idl
, &sbrec_datapath_binding_col_external_ids
);
1192 ovsdb_idl_add_table(ovnsb_idl
, &sbrec_table_port_binding
);
1193 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_datapath
);
1194 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_logical_port
);
1195 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_tunnel_key
);
1196 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_parent_port
);
1197 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_tag
);
1198 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_type
);
1199 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_options
);
1200 add_column_noalert(ovnsb_idl
, &sbrec_port_binding_col_mac
);
1201 ovsdb_idl_add_column(ovnsb_idl
, &sbrec_port_binding_col_chassis
);
1204 * The loop here just runs the IDL in a loop waiting for the seqno to
1205 * change, which indicates that the contents of the db have changed.
1207 * If the contents of the ovn-nb db change, the mappings to the ovn-sb
1208 * db must be recalculated.
1210 * If the contents of the ovn-sb db change, it means the 'up' state of
1211 * a port may have changed, as that's the only type of change ovn-northd is
1215 ovnnb_seqno
= ovsdb_idl_get_seqno(ovnnb_idl
);
1216 ovn_seqno
= ovsdb_idl_get_seqno(ovnsb_idl
);
1219 ovsdb_idl_run(ovnnb_idl
);
1220 ovsdb_idl_run(ovnsb_idl
);
1221 unixctl_server_run(unixctl
);
1223 if (!ovsdb_idl_is_alive(ovnnb_idl
)) {
1224 int retval
= ovsdb_idl_get_last_error(ovnnb_idl
);
1225 VLOG_ERR("%s: database connection failed (%s)",
1226 ovnnb_db
, ovs_retval_to_string(retval
));
1231 if (!ovsdb_idl_is_alive(ovnsb_idl
)) {
1232 int retval
= ovsdb_idl_get_last_error(ovnsb_idl
);
1233 VLOG_ERR("%s: database connection failed (%s)",
1234 ovnsb_db
, ovs_retval_to_string(retval
));
1239 if (ovnnb_seqno
!= ovsdb_idl_get_seqno(ovnnb_idl
)) {
1240 ovnnb_seqno
= ovsdb_idl_get_seqno(ovnnb_idl
);
1241 ovnnb_changes_pending
= true;
1244 if (ovn_seqno
!= ovsdb_idl_get_seqno(ovnsb_idl
)) {
1245 ovn_seqno
= ovsdb_idl_get_seqno(ovnsb_idl
);
1246 ovn_changes_pending
= true;
1250 * If there are any pending changes, we delay recalculating the
1251 * necessary updates until after an existing transaction finishes.
1252 * This avoids the possibility of rapid updates causing ovn-northd to
1253 * never be able to successfully make the corresponding updates to the
1254 * other db. Instead, pending changes are batched up until the next
1255 * time we get a chance to calculate the new state and apply it.
1258 if (ovnnb_changes_pending
&& !ctx
.ovnsb_txn
) {
1260 * The OVN-nb db contents have changed, so create a transaction for
1261 * updating the OVN-sb DB.
1263 ctx
.ovnsb_txn
= ovsdb_idl_txn_create(ctx
.ovnsb_idl
);
1264 ovsdb_idl_txn_add_comment(ctx
.ovnsb_txn
,
1265 "ovn-northd: northbound db changed");
1266 ovnnb_db_changed(&ctx
);
1267 ovnnb_changes_pending
= false;
1270 if (ovn_changes_pending
&& !ctx
.ovnnb_txn
) {
1272 * The OVN-sb db contents have changed, so create a transaction for
1273 * updating the northbound DB.
1275 ctx
.ovnnb_txn
= ovsdb_idl_txn_create(ctx
.ovnnb_idl
);
1276 ovsdb_idl_txn_add_comment(ctx
.ovnnb_txn
,
1277 "ovn-northd: southbound db changed");
1278 ovnsb_db_changed(&ctx
);
1279 ovn_changes_pending
= false;
1282 if (ctx
.ovnnb_txn
) {
1283 enum ovsdb_idl_txn_status txn_status
;
1284 txn_status
= ovsdb_idl_txn_commit(ctx
.ovnnb_txn
);
1285 switch (txn_status
) {
1286 case TXN_UNCOMMITTED
:
1287 case TXN_INCOMPLETE
:
1288 /* Come back around and try to commit this transaction again */
1292 case TXN_NOT_LOCKED
:
1294 /* Something went wrong, so try creating a new transaction. */
1295 ovn_changes_pending
= true;
1298 ovsdb_idl_txn_destroy(ctx
.ovnnb_txn
);
1299 ctx
.ovnnb_txn
= NULL
;
1303 if (ctx
.ovnsb_txn
) {
1304 enum ovsdb_idl_txn_status txn_status
;
1305 txn_status
= ovsdb_idl_txn_commit(ctx
.ovnsb_txn
);
1306 switch (txn_status
) {
1307 case TXN_UNCOMMITTED
:
1308 case TXN_INCOMPLETE
:
1309 /* Come back around and try to commit this transaction again */
1313 case TXN_NOT_LOCKED
:
1315 /* Something went wrong, so try creating a new transaction. */
1316 ovnnb_changes_pending
= true;
1319 ovsdb_idl_txn_destroy(ctx
.ovnsb_txn
);
1320 ctx
.ovnsb_txn
= NULL
;
1324 if (ovnnb_seqno
== ovsdb_idl_get_seqno(ovnnb_idl
) &&
1325 ovn_seqno
== ovsdb_idl_get_seqno(ovnsb_idl
)) {
1326 ovsdb_idl_wait(ovnnb_idl
);
1327 ovsdb_idl_wait(ovnsb_idl
);
1328 if (ctx
.ovnnb_txn
) {
1329 ovsdb_idl_txn_wait(ctx
.ovnnb_txn
);
1331 if (ctx
.ovnsb_txn
) {
1332 ovsdb_idl_txn_wait(ctx
.ovnsb_txn
);
1334 unixctl_server_wait(unixctl
);
1336 poll_immediate_wake();
1340 if (should_service_stop()) {
1345 unixctl_server_destroy(unixctl
);
1346 ovsdb_idl_destroy(ovnsb_idl
);
1347 ovsdb_idl_destroy(ovnnb_idl
);
1356 ovn_northd_exit(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
1357 const char *argv
[] OVS_UNUSED
, void *exiting_
)
1359 bool *exiting
= exiting_
;
1362 unixctl_command_reply(conn
, NULL
);