]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/northd/ovn-northd.c
ovn-northd: Only run idl loop if something changed.
[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);
880fcd14
BP
56\f
57/* Pipeline stages. */
ac0630a2 58
880fcd14
BP
59/* The two pipelines in an OVN logical flow table. */
60enum ovn_pipeline {
61 P_IN, /* Ingress pipeline. */
62 P_OUT /* Egress pipeline. */
63};
091e3af9 64
880fcd14
BP
65/* The two purposes for which ovn-northd uses OVN logical datapaths. */
66enum ovn_datapath_type {
67 DP_SWITCH, /* OVN logical switch. */
68 DP_ROUTER /* OVN logical router. */
091e3af9
JP
69};
70
880fcd14
BP
71/* Returns an "enum ovn_stage" built from the arguments.
72 *
73 * (It's better to use ovn_stage_build() for type-safety reasons, but inline
74 * functions can't be used in enums or switch cases.) */
75#define OVN_STAGE_BUILD(DP_TYPE, PIPELINE, TABLE) \
76 (((DP_TYPE) << 9) | ((PIPELINE) << 8) | (TABLE))
77
78/* A stage within an OVN logical switch or router.
091e3af9 79 *
880fcd14
BP
80 * An "enum ovn_stage" indicates whether the stage is part of a logical switch
81 * or router, whether the stage is part of the ingress or egress pipeline, and
82 * the table within that pipeline. The first three components are combined to
83 * form the stage's full name, e.g. S_SWITCH_IN_PORT_SEC,
84 * S_ROUTER_OUT_DELIVERY. */
85enum ovn_stage {
e0c9e58b
JP
86#define PIPELINE_STAGES \
87 /* Logical switch ingress stages. */ \
88 PIPELINE_STAGE(SWITCH, IN, PORT_SEC, 0, "ls_in_port_sec") \
89 PIPELINE_STAGE(SWITCH, IN, PRE_ACL, 1, "ls_in_pre_acl") \
90 PIPELINE_STAGE(SWITCH, IN, ACL, 2, "ls_in_acl") \
91 PIPELINE_STAGE(SWITCH, IN, L2_LKUP, 3, "ls_in_l2_lkup") \
92 \
93 /* Logical switch egress stages. */ \
94 PIPELINE_STAGE(SWITCH, OUT, PRE_ACL, 0, "ls_out_pre_acl") \
95 PIPELINE_STAGE(SWITCH, OUT, ACL, 1, "ls_out_acl") \
96 PIPELINE_STAGE(SWITCH, OUT, PORT_SEC, 2, "ls_out_port_sec") \
97 \
98 /* Logical router ingress stages. */ \
99 PIPELINE_STAGE(ROUTER, IN, ADMISSION, 0, "lr_in_admission") \
100 PIPELINE_STAGE(ROUTER, IN, IP_INPUT, 1, "lr_in_ip_input") \
101 PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 2, "lr_in_ip_routing") \
102 PIPELINE_STAGE(ROUTER, IN, ARP, 3, "lr_in_arp") \
103 \
104 /* Logical router egress stages. */ \
105 PIPELINE_STAGE(ROUTER, OUT, DELIVERY, 0, "lr_out_delivery")
880fcd14
BP
106
107#define PIPELINE_STAGE(DP_TYPE, PIPELINE, STAGE, TABLE, NAME) \
108 S_##DP_TYPE##_##PIPELINE##_##STAGE \
109 = OVN_STAGE_BUILD(DP_##DP_TYPE, P_##PIPELINE, TABLE),
110 PIPELINE_STAGES
111#undef PIPELINE_STAGE
091e3af9
JP
112};
113
6bb4a18e
JP
114/* Due to various hard-coded priorities need to implement ACLs, the
115 * northbound database supports a smaller range of ACL priorities than
116 * are available to logical flows. This value is added to an ACL
117 * priority to determine the ACL's logical flow priority. */
118#define OVN_ACL_PRI_OFFSET 1000
119
880fcd14
BP
120/* Returns an "enum ovn_stage" built from the arguments. */
121static enum ovn_stage
122ovn_stage_build(enum ovn_datapath_type dp_type, enum ovn_pipeline pipeline,
123 uint8_t table)
124{
125 return OVN_STAGE_BUILD(dp_type, pipeline, table);
126}
127
128/* Returns the pipeline to which 'stage' belongs. */
129static enum ovn_pipeline
130ovn_stage_get_pipeline(enum ovn_stage stage)
131{
132 return (stage >> 8) & 1;
133}
134
135/* Returns the table to which 'stage' belongs. */
136static uint8_t
137ovn_stage_get_table(enum ovn_stage stage)
138{
139 return stage & 0xff;
140}
141
142/* Returns a string name for 'stage'. */
143static const char *
144ovn_stage_to_str(enum ovn_stage stage)
145{
146 switch (stage) {
147#define PIPELINE_STAGE(DP_TYPE, PIPELINE, STAGE, TABLE, NAME) \
148 case S_##DP_TYPE##_##PIPELINE##_##STAGE: return NAME;
149 PIPELINE_STAGES
150#undef PIPELINE_STAGE
151 default: return "<unknown>";
152 }
153}
154\f
ac0630a2
RB
155static void
156usage(void)
157{
158 printf("\
159%s: OVN northbound management daemon\n\
160usage: %s [OPTIONS]\n\
161\n\
162Options:\n\
163 --ovnnb-db=DATABASE connect to ovn-nb database at DATABASE\n\
164 (default: %s)\n\
ec78987f 165 --ovnsb-db=DATABASE connect to ovn-sb database at DATABASE\n\
ac0630a2
RB
166 (default: %s)\n\
167 -h, --help display this help message\n\
168 -o, --options list available options\n\
169 -V, --version display version information\n\
170", program_name, program_name, default_db(), default_db());
67d9b930 171 daemon_usage();
ac0630a2
RB
172 vlog_usage();
173 stream_usage("database", true, true, false);
174}
175\f
5868eb24
BP
176struct tnlid_node {
177 struct hmap_node hmap_node;
178 uint32_t tnlid;
179};
180
181static void
182destroy_tnlids(struct hmap *tnlids)
4edcdcf4 183{
5868eb24
BP
184 struct tnlid_node *node, *next;
185 HMAP_FOR_EACH_SAFE (node, next, hmap_node, tnlids) {
186 hmap_remove(tnlids, &node->hmap_node);
187 free(node);
188 }
189 hmap_destroy(tnlids);
190}
191
192static void
193add_tnlid(struct hmap *set, uint32_t tnlid)
194{
195 struct tnlid_node *node = xmalloc(sizeof *node);
196 hmap_insert(set, &node->hmap_node, hash_int(tnlid, 0));
197 node->tnlid = tnlid;
4edcdcf4
RB
198}
199
4edcdcf4 200static bool
5868eb24 201tnlid_in_use(const struct hmap *set, uint32_t tnlid)
4edcdcf4 202{
5868eb24
BP
203 const struct tnlid_node *node;
204 HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_int(tnlid, 0), set) {
205 if (node->tnlid == tnlid) {
206 return true;
207 }
208 }
209 return false;
210}
4edcdcf4 211
5868eb24
BP
212static uint32_t
213allocate_tnlid(struct hmap *set, const char *name, uint32_t max,
214 uint32_t *hint)
215{
216 for (uint32_t tnlid = *hint + 1; tnlid != *hint;
217 tnlid = tnlid + 1 <= max ? tnlid + 1 : 1) {
218 if (!tnlid_in_use(set, tnlid)) {
219 add_tnlid(set, tnlid);
220 *hint = tnlid;
221 return tnlid;
222 }
4edcdcf4
RB
223 }
224
5868eb24
BP
225 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
226 VLOG_WARN_RL(&rl, "all %s tunnel ids exhausted", name);
227 return 0;
228}
229\f
9975d7be
BP
230/* The 'key' comes from nbs->header_.uuid or nbr->header_.uuid or
231 * sb->external_ids:logical-switch. */
5868eb24
BP
232struct ovn_datapath {
233 struct hmap_node key_node; /* Index on 'key'. */
9975d7be 234 struct uuid key; /* (nbs/nbr)->header_.uuid. */
4edcdcf4 235
9975d7be
BP
236 const struct nbrec_logical_switch *nbs; /* May be NULL. */
237 const struct nbrec_logical_router *nbr; /* May be NULL. */
5868eb24 238 const struct sbrec_datapath_binding *sb; /* May be NULL. */
4edcdcf4 239
5868eb24 240 struct ovs_list list; /* In list of similar records. */
4edcdcf4 241
9975d7be
BP
242 /* Logical router data (digested from nbr). */
243 ovs_be32 gateway;
244
245 /* Logical switch data. */
86e98048
BP
246 struct ovn_port **router_ports;
247 size_t n_router_ports;
9975d7be 248
5868eb24
BP
249 struct hmap port_tnlids;
250 uint32_t port_key_hint;
251
252 bool has_unknown;
253};
254
255static struct ovn_datapath *
256ovn_datapath_create(struct hmap *datapaths, const struct uuid *key,
9975d7be
BP
257 const struct nbrec_logical_switch *nbs,
258 const struct nbrec_logical_router *nbr,
5868eb24
BP
259 const struct sbrec_datapath_binding *sb)
260{
261 struct ovn_datapath *od = xzalloc(sizeof *od);
262 od->key = *key;
263 od->sb = sb;
9975d7be
BP
264 od->nbs = nbs;
265 od->nbr = nbr;
5868eb24
BP
266 hmap_init(&od->port_tnlids);
267 od->port_key_hint = 0;
268 hmap_insert(datapaths, &od->key_node, uuid_hash(&od->key));
269 return od;
270}
271
272static void
273ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
274{
275 if (od) {
276 /* Don't remove od->list. It is used within build_datapaths() as a
277 * private list and once we've exited that function it is not safe to
278 * use it. */
279 hmap_remove(datapaths, &od->key_node);
280 destroy_tnlids(&od->port_tnlids);
86e98048 281 free(od->router_ports);
5868eb24
BP
282 free(od);
283 }
284}
285
286static struct ovn_datapath *
287ovn_datapath_find(struct hmap *datapaths, const struct uuid *uuid)
288{
289 struct ovn_datapath *od;
290
291 HMAP_FOR_EACH_WITH_HASH (od, key_node, uuid_hash(uuid), datapaths) {
292 if (uuid_equals(uuid, &od->key)) {
293 return od;
294 }
295 }
296 return NULL;
297}
298
299static struct ovn_datapath *
300ovn_datapath_from_sbrec(struct hmap *datapaths,
301 const struct sbrec_datapath_binding *sb)
302{
303 struct uuid key;
304
9975d7be
BP
305 if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) &&
306 !smap_get_uuid(&sb->external_ids, "logical-router", &key)) {
5868eb24
BP
307 return NULL;
308 }
309 return ovn_datapath_find(datapaths, &key);
310}
311
312static void
313join_datapaths(struct northd_context *ctx, struct hmap *datapaths,
314 struct ovs_list *sb_only, struct ovs_list *nb_only,
315 struct ovs_list *both)
316{
317 hmap_init(datapaths);
318 list_init(sb_only);
319 list_init(nb_only);
320 list_init(both);
321
322 const struct sbrec_datapath_binding *sb, *sb_next;
323 SBREC_DATAPATH_BINDING_FOR_EACH_SAFE (sb, sb_next, ctx->ovnsb_idl) {
324 struct uuid key;
9975d7be
BP
325 if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) &&
326 !smap_get_uuid(&sb->external_ids, "logical-router", &key)) {
327 ovsdb_idl_txn_add_comment(
328 ctx->ovnsb_txn,
329 "deleting Datapath_Binding "UUID_FMT" that lacks "
330 "external-ids:logical-switch and "
331 "external-ids:logical-router",
332 UUID_ARGS(&sb->header_.uuid));
5868eb24
BP
333 sbrec_datapath_binding_delete(sb);
334 continue;
335 }
336
337 if (ovn_datapath_find(datapaths, &key)) {
338 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
9975d7be
BP
339 VLOG_INFO_RL(
340 &rl, "deleting Datapath_Binding "UUID_FMT" with "
341 "duplicate external-ids:logical-switch/router "UUID_FMT,
342 UUID_ARGS(&sb->header_.uuid), UUID_ARGS(&key));
5868eb24
BP
343 sbrec_datapath_binding_delete(sb);
344 continue;
345 }
346
347 struct ovn_datapath *od = ovn_datapath_create(datapaths, &key,
9975d7be 348 NULL, NULL, sb);
5868eb24
BP
349 list_push_back(sb_only, &od->list);
350 }
351
9975d7be
BP
352 const struct nbrec_logical_switch *nbs;
353 NBREC_LOGICAL_SWITCH_FOR_EACH (nbs, ctx->ovnnb_idl) {
5868eb24 354 struct ovn_datapath *od = ovn_datapath_find(datapaths,
9975d7be 355 &nbs->header_.uuid);
5868eb24 356 if (od) {
9975d7be 357 od->nbs = nbs;
5868eb24
BP
358 list_remove(&od->list);
359 list_push_back(both, &od->list);
360 } else {
9975d7be
BP
361 od = ovn_datapath_create(datapaths, &nbs->header_.uuid,
362 nbs, NULL, NULL);
5868eb24
BP
363 list_push_back(nb_only, &od->list);
364 }
365 }
9975d7be
BP
366
367 const struct nbrec_logical_router *nbr;
368 NBREC_LOGICAL_ROUTER_FOR_EACH (nbr, ctx->ovnnb_idl) {
369 struct ovn_datapath *od = ovn_datapath_find(datapaths,
370 &nbr->header_.uuid);
371 if (od) {
372 if (!od->nbs) {
373 od->nbr = nbr;
374 list_remove(&od->list);
375 list_push_back(both, &od->list);
376 } else {
377 /* Can't happen! */
378 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
379 VLOG_WARN_RL(&rl,
380 "duplicate UUID "UUID_FMT" in OVN_Northbound",
381 UUID_ARGS(&nbr->header_.uuid));
382 continue;
383 }
384 } else {
385 od = ovn_datapath_create(datapaths, &nbr->header_.uuid,
386 NULL, nbr, NULL);
387 list_push_back(nb_only, &od->list);
388 }
389
390 od->gateway = 0;
391 if (nbr->default_gw) {
392 ovs_be32 ip, mask;
393 char *error = ip_parse_masked(nbr->default_gw, &ip, &mask);
394 if (error || !ip || mask != OVS_BE32_MAX) {
395 static struct vlog_rate_limit rl
396 = VLOG_RATE_LIMIT_INIT(5, 1);
397 VLOG_WARN_RL(&rl, "bad 'gateway' %s", nbr->default_gw);
398 free(error);
399 } else {
400 od->gateway = ip;
401 }
402 }
403 }
5868eb24
BP
404}
405
406static uint32_t
407ovn_datapath_allocate_key(struct hmap *dp_tnlids)
408{
409 static uint32_t hint;
410 return allocate_tnlid(dp_tnlids, "datapath", (1u << 24) - 1, &hint);
411}
412
413static void
414build_datapaths(struct northd_context *ctx, struct hmap *datapaths)
415{
416 struct ovs_list sb_only, nb_only, both;
417
418 join_datapaths(ctx, datapaths, &sb_only, &nb_only, &both);
419
420 if (!list_is_empty(&nb_only)) {
421 /* First index the in-use datapath tunnel IDs. */
422 struct hmap dp_tnlids = HMAP_INITIALIZER(&dp_tnlids);
423 struct ovn_datapath *od;
424 LIST_FOR_EACH (od, list, &both) {
425 add_tnlid(&dp_tnlids, od->sb->tunnel_key);
426 }
427
428 /* Add southbound record for each unmatched northbound record. */
429 LIST_FOR_EACH (od, list, &nb_only) {
430 uint16_t tunnel_key = ovn_datapath_allocate_key(&dp_tnlids);
431 if (!tunnel_key) {
432 break;
433 }
434
435 od->sb = sbrec_datapath_binding_insert(ctx->ovnsb_txn);
436
5868eb24 437 char uuid_s[UUID_LEN + 1];
9975d7be
BP
438 sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->key));
439 const char *key = od->nbs ? "logical-switch" : "logical-router";
440 const struct smap id = SMAP_CONST1(&id, key, uuid_s);
aaf881c6 441 sbrec_datapath_binding_set_external_ids(od->sb, &id);
5868eb24
BP
442
443 sbrec_datapath_binding_set_tunnel_key(od->sb, tunnel_key);
444 }
445 destroy_tnlids(&dp_tnlids);
446 }
447
448 /* Delete southbound records without northbound matches. */
449 struct ovn_datapath *od, *next;
450 LIST_FOR_EACH_SAFE (od, next, list, &sb_only) {
451 list_remove(&od->list);
452 sbrec_datapath_binding_delete(od->sb);
453 ovn_datapath_destroy(datapaths, od);
454 }
455}
456\f
457struct ovn_port {
458 struct hmap_node key_node; /* Index on 'key'. */
9975d7be
BP
459 char *key; /* nbs->name, nbr->name, sb->logical_port. */
460 char *json_key; /* 'key', quoted for use in JSON. */
5868eb24 461
9975d7be
BP
462 const struct nbrec_logical_port *nbs; /* May be NULL. */
463 const struct nbrec_logical_router_port *nbr; /* May be NULL. */
464 const struct sbrec_port_binding *sb; /* May be NULL. */
465
466 /* Logical router port data. */
467 ovs_be32 ip, mask; /* 192.168.10.123/24. */
468 ovs_be32 network; /* 192.168.10.0. */
469 ovs_be32 bcast; /* 192.168.10.255. */
470 struct eth_addr mac;
471 struct ovn_port *peer;
5868eb24
BP
472
473 struct ovn_datapath *od;
474
475 struct ovs_list list; /* In list of similar records. */
476};
477
478static struct ovn_port *
479ovn_port_create(struct hmap *ports, const char *key,
9975d7be
BP
480 const struct nbrec_logical_port *nbs,
481 const struct nbrec_logical_router_port *nbr,
5868eb24
BP
482 const struct sbrec_port_binding *sb)
483{
484 struct ovn_port *op = xzalloc(sizeof *op);
9975d7be
BP
485
486 struct ds json_key = DS_EMPTY_INITIALIZER;
487 json_string_escape(key, &json_key);
488 op->json_key = ds_steal_cstr(&json_key);
489
490 op->key = xstrdup(key);
5868eb24 491 op->sb = sb;
9975d7be
BP
492 op->nbs = nbs;
493 op->nbr = nbr;
5868eb24
BP
494 hmap_insert(ports, &op->key_node, hash_string(op->key, 0));
495 return op;
496}
497
498static void
499ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
500{
501 if (port) {
502 /* Don't remove port->list. It is used within build_ports() as a
503 * private list and once we've exited that function it is not safe to
504 * use it. */
505 hmap_remove(ports, &port->key_node);
9975d7be
BP
506 free(port->json_key);
507 free(port->key);
5868eb24
BP
508 free(port);
509 }
510}
511
512static struct ovn_port *
513ovn_port_find(struct hmap *ports, const char *name)
514{
515 struct ovn_port *op;
516
517 HMAP_FOR_EACH_WITH_HASH (op, key_node, hash_string(name, 0), ports) {
518 if (!strcmp(op->key, name)) {
519 return op;
520 }
521 }
522 return NULL;
523}
524
525static uint32_t
526ovn_port_allocate_key(struct ovn_datapath *od)
527{
528 return allocate_tnlid(&od->port_tnlids, "port",
529 (1u << 15) - 1, &od->port_key_hint);
530}
531
532static void
533join_logical_ports(struct northd_context *ctx,
534 struct hmap *datapaths, struct hmap *ports,
535 struct ovs_list *sb_only, struct ovs_list *nb_only,
536 struct ovs_list *both)
537{
538 hmap_init(ports);
539 list_init(sb_only);
540 list_init(nb_only);
541 list_init(both);
542
543 const struct sbrec_port_binding *sb;
544 SBREC_PORT_BINDING_FOR_EACH (sb, ctx->ovnsb_idl) {
545 struct ovn_port *op = ovn_port_create(ports, sb->logical_port,
9975d7be 546 NULL, NULL, sb);
5868eb24
BP
547 list_push_back(sb_only, &op->list);
548 }
549
550 struct ovn_datapath *od;
551 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
552 if (od->nbs) {
553 for (size_t i = 0; i < od->nbs->n_ports; i++) {
554 const struct nbrec_logical_port *nbs = od->nbs->ports[i];
555 struct ovn_port *op = ovn_port_find(ports, nbs->name);
556 if (op) {
557 if (op->nbs || op->nbr) {
558 static struct vlog_rate_limit rl
559 = VLOG_RATE_LIMIT_INIT(5, 1);
560 VLOG_WARN_RL(&rl, "duplicate logical port %s",
561 nbs->name);
562 continue;
563 }
564 op->nbs = nbs;
565 list_remove(&op->list);
566 list_push_back(both, &op->list);
567 } else {
568 op = ovn_port_create(ports, nbs->name, nbs, NULL, NULL);
569 list_push_back(nb_only, &op->list);
570 }
571
572 op->od = od;
573 }
574 } else {
575 for (size_t i = 0; i < od->nbr->n_ports; i++) {
576 const struct nbrec_logical_router_port *nbr
577 = od->nbr->ports[i];
578
579 struct eth_addr mac;
580 if (!eth_addr_from_string(nbr->mac, &mac)) {
581 static struct vlog_rate_limit rl
582 = VLOG_RATE_LIMIT_INIT(5, 1);
583 VLOG_WARN_RL(&rl, "bad 'mac' %s", nbr->mac);
584 continue;
585 }
586
587 ovs_be32 ip, mask;
588 char *error = ip_parse_masked(nbr->network, &ip, &mask);
589 if (error || mask == OVS_BE32_MAX || !ip_is_cidr(mask)) {
590 static struct vlog_rate_limit rl
591 = VLOG_RATE_LIMIT_INIT(5, 1);
592 VLOG_WARN_RL(&rl, "bad 'network' %s", nbr->network);
593 free(error);
594 continue;
595 }
596
00007447 597 struct ovn_port *op = ovn_port_find(ports, nbr->name);
9975d7be
BP
598 if (op) {
599 if (op->nbs || op->nbr) {
600 static struct vlog_rate_limit rl
601 = VLOG_RATE_LIMIT_INIT(5, 1);
602 VLOG_WARN_RL(&rl, "duplicate logical router port %s",
00007447 603 nbr->name);
9975d7be
BP
604 continue;
605 }
606 op->nbr = nbr;
607 list_remove(&op->list);
608 list_push_back(both, &op->list);
609 } else {
00007447 610 op = ovn_port_create(ports, nbr->name, NULL, nbr, NULL);
9975d7be
BP
611 list_push_back(nb_only, &op->list);
612 }
613
614 op->ip = ip;
615 op->mask = mask;
616 op->network = ip & mask;
617 op->bcast = ip | ~mask;
618 op->mac = mac;
619
620 op->od = od;
5868eb24 621 }
9975d7be
BP
622 }
623 }
624
625 /* Connect logical router ports, and logical switch ports of type "router",
626 * to their peers. */
627 struct ovn_port *op;
628 HMAP_FOR_EACH (op, key_node, ports) {
629 if (op->nbs && !strcmp(op->nbs->type, "router")) {
630 const char *peer_name = smap_get(&op->nbs->options, "router-port");
631 if (!peer_name) {
632 continue;
633 }
634
635 struct ovn_port *peer = ovn_port_find(ports, peer_name);
636 if (!peer || !peer->nbr) {
637 continue;
638 }
639
640 peer->peer = op;
641 op->peer = peer;
86e98048
BP
642 op->od->router_ports = xrealloc(
643 op->od->router_ports,
644 sizeof *op->od->router_ports * (op->od->n_router_ports + 1));
645 op->od->router_ports[op->od->n_router_ports++] = op;
9975d7be 646 } else if (op->nbr && op->nbr->peer) {
00007447 647 op->peer = ovn_port_find(ports, op->nbr->name);
5868eb24
BP
648 }
649 }
650}
651
652static void
653ovn_port_update_sbrec(const struct ovn_port *op)
654{
655 sbrec_port_binding_set_datapath(op->sb, op->od->sb);
9975d7be
BP
656 if (op->nbr) {
657 sbrec_port_binding_set_type(op->sb, "patch");
658
659 const char *peer = op->peer ? op->peer->key : "<error>";
660 const struct smap ids = SMAP_CONST1(&ids, "peer", peer);
661 sbrec_port_binding_set_options(op->sb, &ids);
662
663 sbrec_port_binding_set_parent_port(op->sb, NULL);
664 sbrec_port_binding_set_tag(op->sb, NULL, 0);
665 sbrec_port_binding_set_mac(op->sb, NULL, 0);
666 } else {
667 if (strcmp(op->nbs->type, "router")) {
668 sbrec_port_binding_set_type(op->sb, op->nbs->type);
669 sbrec_port_binding_set_options(op->sb, &op->nbs->options);
670 } else {
671 sbrec_port_binding_set_type(op->sb, "patch");
672
673 const char *router_port = smap_get(&op->nbs->options,
674 "router-port");
675 if (!router_port) {
676 router_port = "<error>";
677 }
678 const struct smap ids = SMAP_CONST1(&ids, "peer", router_port);
679 sbrec_port_binding_set_options(op->sb, &ids);
680 }
681 sbrec_port_binding_set_parent_port(op->sb, op->nbs->parent_name);
682 sbrec_port_binding_set_tag(op->sb, op->nbs->tag, op->nbs->n_tag);
683 sbrec_port_binding_set_mac(op->sb, (const char **) op->nbs->addresses,
684 op->nbs->n_addresses);
685 }
5868eb24
BP
686}
687
688static void
689build_ports(struct northd_context *ctx, struct hmap *datapaths,
690 struct hmap *ports)
691{
692 struct ovs_list sb_only, nb_only, both;
693
694 join_logical_ports(ctx, datapaths, ports, &sb_only, &nb_only, &both);
695
696 /* For logical ports that are in both databases, update the southbound
697 * record based on northbound data. Also index the in-use tunnel_keys. */
698 struct ovn_port *op, *next;
699 LIST_FOR_EACH_SAFE (op, next, list, &both) {
700 ovn_port_update_sbrec(op);
701
702 add_tnlid(&op->od->port_tnlids, op->sb->tunnel_key);
703 if (op->sb->tunnel_key > op->od->port_key_hint) {
704 op->od->port_key_hint = op->sb->tunnel_key;
705 }
706 }
707
708 /* Add southbound record for each unmatched northbound record. */
709 LIST_FOR_EACH_SAFE (op, next, list, &nb_only) {
710 uint16_t tunnel_key = ovn_port_allocate_key(op->od);
711 if (!tunnel_key) {
712 continue;
713 }
714
715 op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn);
716 ovn_port_update_sbrec(op);
717
718 sbrec_port_binding_set_logical_port(op->sb, op->key);
719 sbrec_port_binding_set_tunnel_key(op->sb, tunnel_key);
720 }
721
722 /* Delete southbound records without northbound matches. */
723 LIST_FOR_EACH_SAFE(op, next, list, &sb_only) {
724 list_remove(&op->list);
725 sbrec_port_binding_delete(op->sb);
726 ovn_port_destroy(ports, op);
727 }
728}
729\f
730#define OVN_MIN_MULTICAST 32768
731#define OVN_MAX_MULTICAST 65535
732
733struct multicast_group {
734 const char *name;
735 uint16_t key; /* OVN_MIN_MULTICAST...OVN_MAX_MULTICAST. */
736};
737
738#define MC_FLOOD "_MC_flood"
739static const struct multicast_group mc_flood = { MC_FLOOD, 65535 };
740
741#define MC_UNKNOWN "_MC_unknown"
742static const struct multicast_group mc_unknown = { MC_UNKNOWN, 65534 };
743
744static bool
745multicast_group_equal(const struct multicast_group *a,
746 const struct multicast_group *b)
747{
748 return !strcmp(a->name, b->name) && a->key == b->key;
749}
750
751/* Multicast group entry. */
752struct ovn_multicast {
753 struct hmap_node hmap_node; /* Index on 'datapath' and 'key'. */
754 struct ovn_datapath *datapath;
755 const struct multicast_group *group;
756
757 struct ovn_port **ports;
758 size_t n_ports, allocated_ports;
759};
760
761static uint32_t
762ovn_multicast_hash(const struct ovn_datapath *datapath,
763 const struct multicast_group *group)
764{
765 return hash_pointer(datapath, group->key);
766}
767
768static struct ovn_multicast *
769ovn_multicast_find(struct hmap *mcgroups, struct ovn_datapath *datapath,
770 const struct multicast_group *group)
771{
772 struct ovn_multicast *mc;
773
774 HMAP_FOR_EACH_WITH_HASH (mc, hmap_node,
775 ovn_multicast_hash(datapath, group), mcgroups) {
776 if (mc->datapath == datapath
777 && multicast_group_equal(mc->group, group)) {
778 return mc;
4edcdcf4
RB
779 }
780 }
5868eb24
BP
781 return NULL;
782}
783
784static void
785ovn_multicast_add(struct hmap *mcgroups, const struct multicast_group *group,
786 struct ovn_port *port)
787{
788 struct ovn_datapath *od = port->od;
789 struct ovn_multicast *mc = ovn_multicast_find(mcgroups, od, group);
790 if (!mc) {
791 mc = xmalloc(sizeof *mc);
792 hmap_insert(mcgroups, &mc->hmap_node, ovn_multicast_hash(od, group));
793 mc->datapath = od;
794 mc->group = group;
795 mc->n_ports = 0;
796 mc->allocated_ports = 4;
797 mc->ports = xmalloc(mc->allocated_ports * sizeof *mc->ports);
798 }
799 if (mc->n_ports >= mc->allocated_ports) {
800 mc->ports = x2nrealloc(mc->ports, &mc->allocated_ports,
801 sizeof *mc->ports);
802 }
803 mc->ports[mc->n_ports++] = port;
804}
4edcdcf4 805
5868eb24
BP
806static void
807ovn_multicast_destroy(struct hmap *mcgroups, struct ovn_multicast *mc)
808{
809 if (mc) {
810 hmap_remove(mcgroups, &mc->hmap_node);
811 free(mc->ports);
812 free(mc);
813 }
814}
4edcdcf4 815
5868eb24
BP
816static void
817ovn_multicast_update_sbrec(const struct ovn_multicast *mc,
818 const struct sbrec_multicast_group *sb)
819{
820 struct sbrec_port_binding **ports = xmalloc(mc->n_ports * sizeof *ports);
821 for (size_t i = 0; i < mc->n_ports; i++) {
822 ports[i] = CONST_CAST(struct sbrec_port_binding *, mc->ports[i]->sb);
823 }
824 sbrec_multicast_group_set_ports(sb, ports, mc->n_ports);
825 free(ports);
4edcdcf4 826}
bd39395f 827\f
48605550 828/* Logical flow generation.
bd39395f 829 *
48605550 830 * This code generates the Logical_Flow table in the southbound database, as a
bd39395f
BP
831 * function of most of the northbound database.
832 */
833
5868eb24
BP
834struct ovn_lflow {
835 struct hmap_node hmap_node;
bd39395f 836
5868eb24 837 struct ovn_datapath *od;
880fcd14 838 enum ovn_stage stage;
5868eb24
BP
839 uint16_t priority;
840 char *match;
841 char *actions;
bd39395f
BP
842};
843
844static size_t
5868eb24 845ovn_lflow_hash(const struct ovn_lflow *lflow)
bd39395f 846{
5868eb24 847 size_t hash = uuid_hash(&lflow->od->key);
880fcd14 848 hash = hash_2words((lflow->stage << 16) | lflow->priority, hash);
5868eb24
BP
849 hash = hash_string(lflow->match, hash);
850 return hash_string(lflow->actions, hash);
bd39395f
BP
851}
852
5868eb24
BP
853static bool
854ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b)
855{
856 return (a->od == b->od
880fcd14 857 && a->stage == b->stage
5868eb24
BP
858 && a->priority == b->priority
859 && !strcmp(a->match, b->match)
860 && !strcmp(a->actions, b->actions));
861}
862
863static void
864ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
880fcd14 865 enum ovn_stage stage, uint16_t priority,
5868eb24 866 char *match, char *actions)
bd39395f 867{
5868eb24 868 lflow->od = od;
880fcd14 869 lflow->stage = stage;
5868eb24
BP
870 lflow->priority = priority;
871 lflow->match = match;
872 lflow->actions = actions;
bd39395f
BP
873}
874
48605550 875/* Adds a row with the specified contents to the Logical_Flow table. */
bd39395f 876static void
5868eb24 877ovn_lflow_add(struct hmap *lflow_map, struct ovn_datapath *od,
880fcd14 878 enum ovn_stage stage, uint16_t priority,
5868eb24
BP
879 const char *match, const char *actions)
880{
881 struct ovn_lflow *lflow = xmalloc(sizeof *lflow);
880fcd14 882 ovn_lflow_init(lflow, od, stage, priority,
5868eb24
BP
883 xstrdup(match), xstrdup(actions));
884 hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow));
885}
886
887static struct ovn_lflow *
888ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od,
880fcd14 889 enum ovn_stage stage, uint16_t priority,
5868eb24
BP
890 const char *match, const char *actions)
891{
892 struct ovn_lflow target;
880fcd14 893 ovn_lflow_init(&target, od, stage, priority,
5868eb24
BP
894 CONST_CAST(char *, match), CONST_CAST(char *, actions));
895
896 struct ovn_lflow *lflow;
897 HMAP_FOR_EACH_WITH_HASH (lflow, hmap_node, ovn_lflow_hash(&target),
898 lflows) {
899 if (ovn_lflow_equal(lflow, &target)) {
900 return lflow;
bd39395f
BP
901 }
902 }
5868eb24
BP
903 return NULL;
904}
bd39395f 905
5868eb24
BP
906static void
907ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow)
908{
909 if (lflow) {
910 hmap_remove(lflows, &lflow->hmap_node);
911 free(lflow->match);
912 free(lflow->actions);
913 free(lflow);
914 }
bd39395f
BP
915}
916
bd39395f
BP
917/* Appends port security constraints on L2 address field 'eth_addr_field'
918 * (e.g. "eth.src" or "eth.dst") to 'match'. 'port_security', with
919 * 'n_port_security' elements, is the collection of port_security constraints
f7cb14cd 920 * from an OVN_NB Logical_Port row. */
bd39395f
BP
921static void
922build_port_security(const char *eth_addr_field,
923 char **port_security, size_t n_port_security,
924 struct ds *match)
925{
926 size_t base_len = match->length;
927 ds_put_format(match, " && %s == {", eth_addr_field);
928
929 size_t n = 0;
930 for (size_t i = 0; i < n_port_security; i++) {
74ff3298 931 struct eth_addr ea;
f7cb14cd 932
74ff3298 933 if (eth_addr_from_string(port_security[i], &ea)) {
f7cb14cd 934 ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
bd39395f
BP
935 ds_put_char(match, ' ');
936 n++;
937 }
938 }
f7cb14cd 939 ds_chomp(match, ' ');
bd39395f 940 ds_put_cstr(match, "}");
4edcdcf4 941
bd39395f
BP
942 if (!n) {
943 match->length = base_len;
944 }
945}
946
95a9a275
RB
947static bool
948lport_is_enabled(const struct nbrec_logical_port *lport)
949{
950 return !lport->enabled || *lport->enabled;
951}
952
78aab811
JP
953static bool
954has_stateful_acl(struct ovn_datapath *od)
955{
9975d7be
BP
956 for (size_t i = 0; i < od->nbs->n_acls; i++) {
957 struct nbrec_acl *acl = od->nbs->acls[i];
78aab811
JP
958 if (!strcmp(acl->action, "allow-related")) {
959 return true;
960 }
961 }
962
963 return false;
964}
965
966static void
967build_acls(struct ovn_datapath *od, struct hmap *lflows)
968{
969 bool has_stateful = has_stateful_acl(od);
970
971 /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are
972 * allowed by default. */
880fcd14
BP
973 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
974 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;");
78aab811
JP
975
976 /* Ingress and Egress ACL Table (Priority 0): Packets are allowed by
977 * default. A related rule at priority 1 is added below if there
978 * are any stateful ACLs in this datapath. */
880fcd14
BP
979 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1", "next;");
980 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1", "next;");
78aab811
JP
981
982 /* If there are any stateful ACL rules in this dapapath, we must
983 * send all IP packets through the conntrack action, which handles
984 * defragmentation, in order to match L4 headers. */
985 if (has_stateful) {
986 /* Ingress and Egress Pre-ACL Table (Priority 100).
987 *
988 * Regardless of whether the ACL is "from-lport" or "to-lport",
989 * we need rules in both the ingress and egress table, because
990 * the return traffic needs to be followed. */
880fcd14
BP
991 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 100, "ip", "ct_next;");
992 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", "ct_next;");
78aab811
JP
993
994 /* Ingress and Egress ACL Table (Priority 1).
995 *
996 * By default, traffic is allowed. This is partially handled by
997 * the Priority 0 ACL flows added earlier, but we also need to
998 * commit IP flows. This is because, while the initiater's
999 * direction may not have any stateful rules, the server's may
1000 * and then its return traffic would not have an associated
1001 * conntrack entry and would return "+invalid". */
880fcd14 1002 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "ip",
78aab811 1003 "ct_commit; next;");
880fcd14 1004 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "ip",
78aab811
JP
1005 "ct_commit; next;");
1006
1007 /* Ingress and Egress ACL Table (Priority 65535).
1008 *
1009 * Always drop traffic that's in an invalid state. This is
1010 * enforced at a higher priority than ACLs can be defined. */
880fcd14 1011 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
78aab811 1012 "ct.inv", "drop;");
880fcd14 1013 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
78aab811
JP
1014 "ct.inv", "drop;");
1015
1016 /* Ingress and Egress ACL Table (Priority 65535).
1017 *
1018 * Always allow traffic that is established to a committed
1019 * conntrack entry. This is enforced at a higher priority than
1020 * ACLs can be defined. */
880fcd14 1021 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
78aab811
JP
1022 "ct.est && !ct.rel && !ct.new && !ct.inv",
1023 "next;");
880fcd14 1024 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
78aab811
JP
1025 "ct.est && !ct.rel && !ct.new && !ct.inv",
1026 "next;");
1027
1028 /* Ingress and Egress ACL Table (Priority 65535).
1029 *
1030 * Always allow traffic that is related to an existing conntrack
1031 * entry. This is enforced at a higher priority than ACLs can
1032 * be defined.
1033 *
1034 * NOTE: This does not support related data sessions (eg,
1035 * a dynamically negotiated FTP data channel), but will allow
1036 * related traffic such as an ICMP Port Unreachable through
1037 * that's generated from a non-listening UDP port. */
880fcd14 1038 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
78aab811
JP
1039 "!ct.est && ct.rel && !ct.new && !ct.inv",
1040 "next;");
880fcd14 1041 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
78aab811
JP
1042 "!ct.est && ct.rel && !ct.new && !ct.inv",
1043 "next;");
1044 }
1045
1046 /* Ingress or Egress ACL Table (Various priorities). */
9975d7be
BP
1047 for (size_t i = 0; i < od->nbs->n_acls; i++) {
1048 struct nbrec_acl *acl = od->nbs->acls[i];
78aab811 1049 bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
880fcd14 1050 enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : S_SWITCH_OUT_ACL;
78aab811
JP
1051
1052 if (!strcmp(acl->action, "allow")) {
1053 /* If there are any stateful flows, we must even commit "allow"
1054 * actions. This is because, while the initiater's
1055 * direction may not have any stateful rules, the server's
1056 * may and then its return traffic would not have an
1057 * associated conntrack entry and would return "+invalid". */
1058 const char *actions = has_stateful ? "ct_commit; next;" : "next;";
6bb4a18e
JP
1059 ovn_lflow_add(lflows, od, stage,
1060 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1061 acl->match, actions);
1062 } else if (!strcmp(acl->action, "allow-related")) {
1063 struct ds match = DS_EMPTY_INITIALIZER;
1064
1065 /* Commit the connection tracking entry, which allows all
1066 * other traffic related to this entry to flow due to the
1067 * 65535 priority flow defined earlier. */
1068 ds_put_format(&match, "ct.new && (%s)", acl->match);
6bb4a18e
JP
1069 ovn_lflow_add(lflows, od, stage,
1070 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1071 ds_cstr(&match), "ct_commit; next;");
1072
1073 ds_destroy(&match);
1074 } else if (!strcmp(acl->action, "drop")) {
6bb4a18e
JP
1075 ovn_lflow_add(lflows, od, stage,
1076 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1077 acl->match, "drop;");
1078 } else if (!strcmp(acl->action, "reject")) {
1079 /* xxx Need to support "reject". */
1080 VLOG_INFO("reject is not a supported action");
6bb4a18e
JP
1081 ovn_lflow_add(lflows, od, stage,
1082 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1083 acl->match, "drop;");
1084 }
1085 }
1086}
1087
bd39395f 1088static void
9975d7be
BP
1089build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
1090 struct hmap *lflows, struct hmap *mcgroups)
bd39395f 1091{
5cff6b99
BP
1092 /* This flow table structure is documented in ovn-northd(8), so please
1093 * update ovn-northd.8.xml if you change anything. */
1094
9975d7be
BP
1095 /* Build pre-ACL and ACL tables for both ingress and egress.
1096 * Ingress tables 1 and 2. Egress tables 0 and 1. */
5868eb24
BP
1097 struct ovn_datapath *od;
1098 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1099 if (!od->nbs) {
1100 continue;
1101 }
1102
1103 build_acls(od, lflows);
1104 }
1105
1106 /* Logical switch ingress table 0: Admission control framework (priority
1107 * 100). */
1108 HMAP_FOR_EACH (od, key_node, datapaths) {
1109 if (!od->nbs) {
1110 continue;
1111 }
1112
bd39395f 1113 /* Logical VLANs not supported. */
9975d7be 1114 ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC, 100, "vlan.present",
091e3af9 1115 "drop;");
bd39395f
BP
1116
1117 /* Broadcast/multicast source address is invalid. */
9975d7be 1118 ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC, 100, "eth.src[40]",
091e3af9 1119 "drop;");
bd39395f 1120
35060cdc
BP
1121 /* Port security flows have priority 50 (see below) and will continue
1122 * to the next table if packet source is acceptable. */
bd39395f
BP
1123 }
1124
9975d7be 1125 /* Logical switch ingress table 0: Ingress port security (priority 50). */
5868eb24
BP
1126 struct ovn_port *op;
1127 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1128 if (!op->nbs) {
1129 continue;
1130 }
1131
1132 if (!lport_is_enabled(op->nbs)) {
96af668a
BP
1133 /* Drop packets from disabled logical ports (since logical flow
1134 * tables are default-drop). */
1135 continue;
1136 }
1137
5868eb24 1138 struct ds match = DS_EMPTY_INITIALIZER;
9975d7be 1139 ds_put_format(&match, "inport == %s", op->json_key);
5868eb24 1140 build_port_security("eth.src",
9975d7be 1141 op->nbs->port_security, op->nbs->n_port_security,
5868eb24 1142 &match);
9975d7be 1143 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC, 50,
96af668a 1144 ds_cstr(&match), "next;");
5868eb24
BP
1145 ds_destroy(&match);
1146 }
445a266a 1147
23508e79 1148 /* Ingress table 3: Destination lookup, broadcast and multicast handling
5868eb24
BP
1149 * (priority 100). */
1150 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1151 if (!op->nbs) {
1152 continue;
1153 }
1154
1155 if (lport_is_enabled(op->nbs)) {
1156 ovn_multicast_add(mcgroups, &mc_flood, op);
445a266a 1157 }
5868eb24
BP
1158 }
1159 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1160 if (!od->nbs) {
1161 continue;
1162 }
1163
1164 ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 100, "eth.mcast",
5868eb24 1165 "outport = \""MC_FLOOD"\"; output;");
bd39395f 1166 }
bd39395f 1167
78aab811 1168 /* Ingress table 3: Destination lookup, unicast handling (priority 50), */
5868eb24 1169 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1170 if (!op->nbs) {
1171 continue;
1172 }
1173
1174 for (size_t i = 0; i < op->nbs->n_addresses; i++) {
74ff3298 1175 struct eth_addr mac;
5868eb24 1176
9975d7be 1177 if (eth_addr_from_string(op->nbs->addresses[i], &mac)) {
5868eb24
BP
1178 struct ds match, actions;
1179
1180 ds_init(&match);
9975d7be
BP
1181 ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
1182 ETH_ADDR_ARGS(mac));
5868eb24
BP
1183
1184 ds_init(&actions);
9975d7be
BP
1185 ds_put_format(&actions, "outport = %s; output;", op->json_key);
1186 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50,
5868eb24
BP
1187 ds_cstr(&match), ds_cstr(&actions));
1188 ds_destroy(&actions);
1189 ds_destroy(&match);
9975d7be
BP
1190 } else if (!strcmp(op->nbs->addresses[i], "unknown")) {
1191 if (lport_is_enabled(op->nbs)) {
1192 ovn_multicast_add(mcgroups, &mc_unknown, op);
96af668a
BP
1193 op->od->has_unknown = true;
1194 }
5868eb24
BP
1195 } else {
1196 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
445a266a 1197
2fa326a3
BP
1198 VLOG_INFO_RL(&rl,
1199 "%s: invalid syntax '%s' in addresses column",
9975d7be 1200 op->nbs->name, op->nbs->addresses[i]);
445a266a
BP
1201 }
1202 }
bd39395f
BP
1203 }
1204
78aab811 1205 /* Ingress table 3: Destination lookup for unknown MACs (priority 0). */
5868eb24 1206 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1207 if (!od->nbs) {
1208 continue;
1209 }
1210
5868eb24 1211 if (od->has_unknown) {
9975d7be 1212 ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1",
5868eb24 1213 "outport = \""MC_UNKNOWN"\"; output;");
445a266a 1214 }
bd39395f
BP
1215 }
1216
78aab811 1217 /* Egress table 2: Egress port security multicast/broadcast (priority
5868eb24
BP
1218 * 100). */
1219 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1220 if (!od->nbs) {
1221 continue;
1222 }
1223
1224 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PORT_SEC, 100, "eth.mcast",
091e3af9 1225 "output;");
48f42f3a
RB
1226 }
1227
78aab811 1228 /* Egress table 2: Egress port security (priorities 50 and 150).
d770a830
BP
1229 *
1230 * Priority 50 rules implement port security for enabled logical port.
1231 *
1232 * Priority 150 rules drop packets to disabled logical ports, so that they
1233 * don't even receive multicast or broadcast packets. */
5868eb24 1234 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1235 if (!op->nbs) {
1236 continue;
1237 }
1238
1239 struct ds match = DS_EMPTY_INITIALIZER;
1240 ds_put_format(&match, "outport == %s", op->json_key);
1241 if (lport_is_enabled(op->nbs)) {
1242 build_port_security("eth.dst", op->nbs->port_security,
1243 op->nbs->n_port_security, &match);
1244 ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC, 50,
d770a830
BP
1245 ds_cstr(&match), "output;");
1246 } else {
9975d7be 1247 ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC, 150,
d770a830
BP
1248 ds_cstr(&match), "drop;");
1249 }
eb00399e 1250
5868eb24 1251 ds_destroy(&match);
eb00399e 1252 }
9975d7be 1253}
eb00399e 1254
9975d7be
BP
1255static bool
1256lrport_is_enabled(const struct nbrec_logical_router_port *lrport)
1257{
1258 return !lrport->enabled || *lrport->enabled;
1259}
1260
1261static void
1262add_route(struct hmap *lflows, struct ovn_datapath *od,
1263 ovs_be32 network, ovs_be32 mask, ovs_be32 gateway)
1264{
1265 char *match = xasprintf("ip4.dst == "IP_FMT"/"IP_FMT,
1266 IP_ARGS(network), IP_ARGS(mask));
1267
1268 struct ds actions = DS_EMPTY_INITIALIZER;
47f3b59b 1269 ds_put_cstr(&actions, "ip.ttl--; reg0 = ");
9975d7be
BP
1270 if (gateway) {
1271 ds_put_format(&actions, IP_FMT, IP_ARGS(gateway));
1272 } else {
1273 ds_put_cstr(&actions, "ip4.dst");
1274 }
1275 ds_put_cstr(&actions, "; next;");
1276
1277 /* The priority here is calculated to implement longest-prefix-match
1278 * routing. */
1279 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_ROUTING,
1280 count_1bits(ntohl(mask)), match, ds_cstr(&actions));
1281 ds_destroy(&actions);
1282 free(match);
1283}
1284
1285static void
1286build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
1287 struct hmap *lflows)
1288{
1289 /* This flow table structure is documented in ovn-northd(8), so please
1290 * update ovn-northd.8.xml if you change anything. */
1291
9975d7be
BP
1292 /* Logical router ingress table 0: Admission control framework. */
1293 struct ovn_datapath *od;
1294 HMAP_FOR_EACH (od, key_node, datapaths) {
1295 if (!od->nbr) {
1296 continue;
1297 }
1298
1299 /* Logical VLANs not supported.
1300 * Broadcast/multicast source address is invalid. */
1301 ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100,
1302 "vlan.present || eth.src[40]", "drop;");
1303 }
1304
1305 /* Logical router ingress table 0: match (priority 50). */
1306 struct ovn_port *op;
1307 HMAP_FOR_EACH (op, key_node, ports) {
1308 if (!op->nbr) {
1309 continue;
1310 }
1311
1312 if (!lrport_is_enabled(op->nbr)) {
1313 /* Drop packets from disabled logical ports (since logical flow
1314 * tables are default-drop). */
1315 continue;
1316 }
1317
1318 char *match = xasprintf(
1319 "(eth.mcast || eth.dst == "ETH_ADDR_FMT") && inport == %s",
1320 ETH_ADDR_ARGS(op->mac), op->json_key);
1321 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50,
1322 match, "next;");
e2229be9 1323 free(match);
9975d7be
BP
1324 }
1325
1326 /* Logical router ingress table 1: IP Input. */
78aab811 1327 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1328 if (!od->nbr) {
1329 continue;
1330 }
1331
1332 /* L3 admission control: drop multicast and broadcast source, localhost
1333 * source or destination, and zero network source or destination
1334 * (priority 100). */
1335 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 100,
1336 "ip4.mcast || "
1337 "ip4.src == 255.255.255.255 || "
1338 "ip4.src == 127.0.0.0/8 || "
1339 "ip4.dst == 127.0.0.0/8 || "
1340 "ip4.src == 0.0.0.0/8 || "
1341 "ip4.dst == 0.0.0.0/8",
1342 "drop;");
1343
1344 /* Drop Ethernet local broadcast. By definition this traffic should
1345 * not be forwarded.*/
1346 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
1347 "eth.bcast", "drop;");
1348
1349 /* Drop IP multicast. */
1350 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
1351 "ip4.mcast", "drop;");
1352
1353 /* TTL discard.
1354 *
1355 * XXX Need to send ICMP time exceeded if !ip.later_frag. */
1356 char *match = xasprintf("ip4 && ip.ttl == {0, 1}");
1357 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, match, "drop;");
1358 free(match);
1359
1360 /* Pass other traffic not already handled to the next table for
1361 * routing. */
1362 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;");
78aab811
JP
1363 }
1364
9975d7be
BP
1365 HMAP_FOR_EACH (op, key_node, ports) {
1366 if (!op->nbr) {
1367 continue;
1368 }
1369
1370 /* L3 admission control: drop packets that originate from an IP address
1371 * owned by the router or a broadcast address known to the router
1372 * (priority 100). */
1373 char *match = xasprintf("ip4.src == {"IP_FMT", "IP_FMT"}",
1374 IP_ARGS(op->ip), IP_ARGS(op->bcast));
1375 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
1376 match, "drop;");
1377 free(match);
1378
dd7652e6
JP
1379 /* ICMP echo reply. These flows reply to ICMP echo requests
1380 * received for the router's IP address. */
1381 match = xasprintf(
1382 "inport == %s && (ip4.dst == "IP_FMT" || ip4.dst == "IP_FMT") && "
1383 "icmp4.type == 8 && icmp4.code == 0",
1384 op->json_key, IP_ARGS(op->ip), IP_ARGS(op->bcast));
1385 char *actions = xasprintf(
1386 "ip4.dst = ip4.src; "
1387 "ip4.src = "IP_FMT"; "
1388 "ip.ttl = 255; "
1389 "icmp4.type = 0; "
1390 "inport = \"\"; /* Allow sending out inport. */ "
1391 "next; ",
1392 IP_ARGS(op->ip));
1393 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
1394 match, actions);
1395 free(match);
1396 free(actions);
1397
9975d7be
BP
1398 /* ARP reply. These flows reply to ARP requests for the router's own
1399 * IP address. */
1400 match = xasprintf(
1401 "inport == %s && arp.tpa == "IP_FMT" && arp.op == 1",
1402 op->json_key, IP_ARGS(op->ip));
dd7652e6 1403 actions = xasprintf(
9975d7be
BP
1404 "eth.dst = eth.src; "
1405 "eth.src = "ETH_ADDR_FMT"; "
1406 "arp.op = 2; /* ARP reply */ "
1407 "arp.tha = arp.sha; "
1408 "arp.sha = "ETH_ADDR_FMT"; "
1409 "arp.tpa = arp.spa; "
1410 "arp.spa = "IP_FMT"; "
1411 "outport = %s; "
1412 "inport = \"\"; /* Allow sending out inport. */ "
1413 "output;",
1414 ETH_ADDR_ARGS(op->mac),
1415 ETH_ADDR_ARGS(op->mac),
1416 IP_ARGS(op->ip),
1417 op->json_key);
1418 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
1419 match, actions);
abcec848
JP
1420 free(match);
1421 free(actions);
9975d7be
BP
1422
1423 /* Drop IP traffic to this router. */
1424 match = xasprintf("ip4.dst == "IP_FMT, IP_ARGS(op->ip));
1425 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60,
1426 match, "drop;");
1427 free(match);
1428 }
1429
1430 /* Logical router ingress table 2: IP Routing.
1431 *
1432 * A packet that arrives at this table is an IP packet that should be
1433 * routed to the address in ip4.dst. This table sets reg0 to the next-hop
1434 * IP address (leaving ip4.dst, the packet’s final destination, unchanged)
1435 * and advances to the next table for ARP resolution. */
1436 HMAP_FOR_EACH (op, key_node, ports) {
1437 if (!op->nbr) {
1438 continue;
1439 }
1440
1441 add_route(lflows, op->od, op->network, op->mask, 0);
1442 }
1443 HMAP_FOR_EACH (od, key_node, datapaths) {
1444 if (!od->nbr) {
1445 continue;
1446 }
1447
1448 if (od->gateway) {
1449 add_route(lflows, od, 0, 0, od->gateway);
1450 }
1451 }
1452 /* XXX destination unreachable */
1453
1454 /* Local router ingress table 3: ARP Resolution.
1455 *
1456 * Any packet that reaches this table is an IP packet whose next-hop IP
1457 * address is in reg0. (ip4.dst is the final destination.) This table
1458 * resolves the IP address in reg0 into an output port in outport and an
1459 * Ethernet address in eth.dst. */
1460 HMAP_FOR_EACH (op, key_node, ports) {
1461 if (op->nbr) {
1462 /* XXX ARP for neighboring router */
86e98048 1463 } else if (op->od->n_router_ports) {
9975d7be
BP
1464 for (size_t i = 0; i < op->nbs->n_addresses; i++) {
1465 struct eth_addr ea;
1466 ovs_be32 ip;
1467
1468 if (ovs_scan(op->nbs->addresses[i],
1469 ETH_ADDR_SCAN_FMT" "IP_SCAN_FMT,
1470 ETH_ADDR_SCAN_ARGS(ea), IP_SCAN_ARGS(&ip))) {
86e98048
BP
1471 for (size_t j = 0; j < op->od->n_router_ports; j++) {
1472 /* Get the Logical_Router_Port that the Logical_Port is
1473 * connected to, as 'peer'. */
1474 const char *peer_name = smap_get(
1475 &op->od->router_ports[j]->nbs->options,
1476 "router-port");
1477 if (!peer_name) {
1478 continue;
1479 }
1480
1481 struct ovn_port *peer
1482 = ovn_port_find(ports, peer_name);
1483 if (!peer || !peer->nbr) {
1484 continue;
1485 }
1486
1487 /* Make sure that 'ip' is in 'peer''s network. */
1488 if ((ip ^ peer->network) & peer->mask) {
1489 continue;
1490 }
1491
1492 char *match = xasprintf("reg0 == "IP_FMT, IP_ARGS(ip));
1493 char *actions = xasprintf("eth.src = "ETH_ADDR_FMT"; "
1494 "eth.dst = "ETH_ADDR_FMT"; "
1495 "outport = %s; "
1496 "output;",
1497 ETH_ADDR_ARGS(peer->mac),
1498 ETH_ADDR_ARGS(ea),
1499 peer->json_key);
1500 ovn_lflow_add(lflows, peer->od,
1501 S_ROUTER_IN_ARP, 200, match, actions);
1502 free(actions);
1503 free(match);
1504 break;
1505 }
9975d7be
BP
1506 }
1507 }
1508 }
1509 }
1510
1511 /* Logical router egress table 0: Delivery (priority 100).
1512 *
1513 * Priority 100 rules deliver packets to enabled logical ports. */
1514 HMAP_FOR_EACH (op, key_node, ports) {
1515 if (!op->nbr) {
1516 continue;
1517 }
1518
1519 if (!lrport_is_enabled(op->nbr)) {
1520 /* Drop packets to disabled logical ports (since logical flow
1521 * tables are default-drop). */
1522 continue;
1523 }
1524
1525 char *match = xasprintf("outport == %s", op->json_key);
1526 ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100,
1527 match, "output;");
1528 free(match);
1529 }
1530}
1531
1532/* Updates the Logical_Flow and Multicast_Group tables in the OVN_SB database,
1533 * constructing their contents based on the OVN_NB database. */
1534static void
1535build_lflows(struct northd_context *ctx, struct hmap *datapaths,
1536 struct hmap *ports)
1537{
1538 struct hmap lflows = HMAP_INITIALIZER(&lflows);
1539 struct hmap mcgroups = HMAP_INITIALIZER(&mcgroups);
1540
1541 build_lswitch_flows(datapaths, ports, &lflows, &mcgroups);
1542 build_lrouter_flows(datapaths, ports, &lflows);
1543
5868eb24
BP
1544 /* Push changes to the Logical_Flow table to database. */
1545 const struct sbrec_logical_flow *sbflow, *next_sbflow;
1546 SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow, next_sbflow, ctx->ovnsb_idl) {
1547 struct ovn_datapath *od
1548 = ovn_datapath_from_sbrec(datapaths, sbflow->logical_datapath);
1549 if (!od) {
1550 sbrec_logical_flow_delete(sbflow);
1551 continue;
eb00399e 1552 }
eb00399e 1553
9975d7be 1554 enum ovn_datapath_type dp_type = od->nbs ? DP_SWITCH : DP_ROUTER;
880fcd14
BP
1555 enum ovn_pipeline pipeline
1556 = !strcmp(sbflow->pipeline, "ingress") ? P_IN : P_OUT;
5868eb24 1557 struct ovn_lflow *lflow = ovn_lflow_find(
880fcd14
BP
1558 &lflows, od, ovn_stage_build(dp_type, pipeline, sbflow->table_id),
1559 sbflow->priority, sbflow->match, sbflow->actions);
5868eb24
BP
1560 if (lflow) {
1561 ovn_lflow_destroy(&lflows, lflow);
1562 } else {
1563 sbrec_logical_flow_delete(sbflow);
4edcdcf4
RB
1564 }
1565 }
5868eb24
BP
1566 struct ovn_lflow *lflow, *next_lflow;
1567 HMAP_FOR_EACH_SAFE (lflow, next_lflow, hmap_node, &lflows) {
880fcd14
BP
1568 enum ovn_pipeline pipeline = ovn_stage_get_pipeline(lflow->stage);
1569 uint8_t table = ovn_stage_get_table(lflow->stage);
1570
5868eb24
BP
1571 sbflow = sbrec_logical_flow_insert(ctx->ovnsb_txn);
1572 sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb);
9975d7be
BP
1573 sbrec_logical_flow_set_pipeline(
1574 sbflow, pipeline == P_IN ? "ingress" : "egress");
880fcd14 1575 sbrec_logical_flow_set_table_id(sbflow, table);
5868eb24
BP
1576 sbrec_logical_flow_set_priority(sbflow, lflow->priority);
1577 sbrec_logical_flow_set_match(sbflow, lflow->match);
1578 sbrec_logical_flow_set_actions(sbflow, lflow->actions);
091e3af9 1579
880fcd14
BP
1580 const struct smap ids = SMAP_CONST1(&ids, "stage-name",
1581 ovn_stage_to_str(lflow->stage));
aaf881c6 1582 sbrec_logical_flow_set_external_ids(sbflow, &ids);
091e3af9 1583
5868eb24 1584 ovn_lflow_destroy(&lflows, lflow);
eb00399e 1585 }
5868eb24
BP
1586 hmap_destroy(&lflows);
1587
1588 /* Push changes to the Multicast_Group table to database. */
1589 const struct sbrec_multicast_group *sbmc, *next_sbmc;
1590 SBREC_MULTICAST_GROUP_FOR_EACH_SAFE (sbmc, next_sbmc, ctx->ovnsb_idl) {
1591 struct ovn_datapath *od = ovn_datapath_from_sbrec(datapaths,
1592 sbmc->datapath);
1593 if (!od) {
1594 sbrec_multicast_group_delete(sbmc);
1595 continue;
1596 }
eb00399e 1597
5868eb24
BP
1598 struct multicast_group group = { .name = sbmc->name,
1599 .key = sbmc->tunnel_key };
1600 struct ovn_multicast *mc = ovn_multicast_find(&mcgroups, od, &group);
1601 if (mc) {
1602 ovn_multicast_update_sbrec(mc, sbmc);
1603 ovn_multicast_destroy(&mcgroups, mc);
1604 } else {
1605 sbrec_multicast_group_delete(sbmc);
1606 }
1607 }
1608 struct ovn_multicast *mc, *next_mc;
1609 HMAP_FOR_EACH_SAFE (mc, next_mc, hmap_node, &mcgroups) {
1610 sbmc = sbrec_multicast_group_insert(ctx->ovnsb_txn);
1611 sbrec_multicast_group_set_datapath(sbmc, mc->datapath->sb);
1612 sbrec_multicast_group_set_name(sbmc, mc->group->name);
1613 sbrec_multicast_group_set_tunnel_key(sbmc, mc->group->key);
1614 ovn_multicast_update_sbrec(mc, sbmc);
1615 ovn_multicast_destroy(&mcgroups, mc);
4edcdcf4 1616 }
5868eb24 1617 hmap_destroy(&mcgroups);
4edcdcf4 1618}
5868eb24 1619\f
4edcdcf4 1620static void
331e7aef 1621ovnnb_db_run(struct northd_context *ctx)
4edcdcf4 1622{
331e7aef
NS
1623 if (!ctx->ovnsb_txn) {
1624 return;
1625 }
1626 VLOG_DBG("ovn-nb db contents may have changed.");
5868eb24
BP
1627 struct hmap datapaths, ports;
1628 build_datapaths(ctx, &datapaths);
1629 build_ports(ctx, &datapaths, &ports);
1630 build_lflows(ctx, &datapaths, &ports);
1631
1632 struct ovn_datapath *dp, *next_dp;
1633 HMAP_FOR_EACH_SAFE (dp, next_dp, key_node, &datapaths) {
1634 ovn_datapath_destroy(&datapaths, dp);
1635 }
1636 hmap_destroy(&datapaths);
1637
1638 struct ovn_port *port, *next_port;
1639 HMAP_FOR_EACH_SAFE (port, next_port, key_node, &ports) {
1640 ovn_port_destroy(&ports, port);
1641 }
1642 hmap_destroy(&ports);
ac0630a2
RB
1643}
1644
f93818dd
RB
1645/*
1646 * The only change we get notified about is if the 'chassis' column of the
dcda6e0d
BP
1647 * 'Port_Binding' table changes. When this column is not empty, it means we
1648 * need to set the corresponding logical port as 'up' in the northbound DB.
f93818dd 1649 */
ac0630a2 1650static void
331e7aef 1651ovnsb_db_run(struct northd_context *ctx)
ac0630a2 1652{
331e7aef
NS
1653 if (!ctx->ovnnb_txn) {
1654 return;
1655 }
fc3113bc 1656 struct hmap lports_hmap;
5868eb24
BP
1657 const struct sbrec_port_binding *sb;
1658 const struct nbrec_logical_port *nb;
fc3113bc
RB
1659
1660 struct lport_hash_node {
1661 struct hmap_node node;
5868eb24 1662 const struct nbrec_logical_port *nb;
fc3113bc 1663 } *hash_node, *hash_node_next;
f93818dd
RB
1664
1665 VLOG_DBG("Recalculating port up states for ovn-nb db.");
1666
fc3113bc 1667 hmap_init(&lports_hmap);
f93818dd 1668
5868eb24 1669 NBREC_LOGICAL_PORT_FOR_EACH(nb, ctx->ovnnb_idl) {
fc3113bc 1670 hash_node = xzalloc(sizeof *hash_node);
5868eb24
BP
1671 hash_node->nb = nb;
1672 hmap_insert(&lports_hmap, &hash_node->node, hash_string(nb->name, 0));
fc3113bc
RB
1673 }
1674
5868eb24
BP
1675 SBREC_PORT_BINDING_FOR_EACH(sb, ctx->ovnsb_idl) {
1676 nb = NULL;
fc3113bc 1677 HMAP_FOR_EACH_WITH_HASH(hash_node, node,
5868eb24
BP
1678 hash_string(sb->logical_port, 0),
1679 &lports_hmap) {
1680 if (!strcmp(sb->logical_port, hash_node->nb->name)) {
1681 nb = hash_node->nb;
fc3113bc
RB
1682 break;
1683 }
f93818dd
RB
1684 }
1685
5868eb24 1686 if (!nb) {
dcda6e0d 1687 /* The logical port doesn't exist for this port binding. This can
2e2762d4 1688 * happen under normal circumstances when ovn-northd hasn't gotten
dcda6e0d 1689 * around to pruning the Port_Binding yet. */
f93818dd
RB
1690 continue;
1691 }
1692
5868eb24 1693 if (sb->chassis && (!nb->up || !*nb->up)) {
f93818dd 1694 bool up = true;
5868eb24
BP
1695 nbrec_logical_port_set_up(nb, &up, 1);
1696 } else if (!sb->chassis && (!nb->up || *nb->up)) {
f93818dd 1697 bool up = false;
5868eb24 1698 nbrec_logical_port_set_up(nb, &up, 1);
f93818dd
RB
1699 }
1700 }
fc3113bc
RB
1701
1702 HMAP_FOR_EACH_SAFE(hash_node, hash_node_next, node, &lports_hmap) {
1703 hmap_remove(&lports_hmap, &hash_node->node);
1704 free(hash_node);
1705 }
1706 hmap_destroy(&lports_hmap);
ac0630a2
RB
1707}
1708\f
45f98d4c
RB
1709
1710static char *default_db_;
1711
ac0630a2
RB
1712static const char *
1713default_db(void)
1714{
45f98d4c
RB
1715 if (!default_db_) {
1716 default_db_ = xasprintf("unix:%s/db.sock", ovs_rundir());
ac0630a2 1717 }
45f98d4c 1718 return default_db_;
ac0630a2
RB
1719}
1720
1721static void
1722parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
1723{
1724 enum {
67d9b930 1725 DAEMON_OPTION_ENUMS,
ac0630a2
RB
1726 VLOG_OPTION_ENUMS,
1727 };
1728 static const struct option long_options[] = {
ec78987f 1729 {"ovnsb-db", required_argument, NULL, 'd'},
ac0630a2
RB
1730 {"ovnnb-db", required_argument, NULL, 'D'},
1731 {"help", no_argument, NULL, 'h'},
1732 {"options", no_argument, NULL, 'o'},
1733 {"version", no_argument, NULL, 'V'},
67d9b930 1734 DAEMON_LONG_OPTIONS,
ac0630a2
RB
1735 VLOG_LONG_OPTIONS,
1736 STREAM_SSL_LONG_OPTIONS,
1737 {NULL, 0, NULL, 0},
1738 };
1739 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
1740
1741 for (;;) {
1742 int c;
1743
1744 c = getopt_long(argc, argv, short_options, long_options, NULL);
1745 if (c == -1) {
1746 break;
1747 }
1748
1749 switch (c) {
67d9b930 1750 DAEMON_OPTION_HANDLERS;
ac0630a2
RB
1751 VLOG_OPTION_HANDLERS;
1752 STREAM_SSL_OPTION_HANDLERS;
1753
1754 case 'd':
ec78987f 1755 ovnsb_db = optarg;
ac0630a2
RB
1756 break;
1757
1758 case 'D':
1759 ovnnb_db = optarg;
1760 break;
1761
1762 case 'h':
1763 usage();
1764 exit(EXIT_SUCCESS);
1765
1766 case 'o':
1767 ovs_cmdl_print_options(long_options);
1768 exit(EXIT_SUCCESS);
1769
1770 case 'V':
1771 ovs_print_version(0, 0);
1772 exit(EXIT_SUCCESS);
1773
1774 default:
1775 break;
1776 }
1777 }
1778
ec78987f
JP
1779 if (!ovnsb_db) {
1780 ovnsb_db = default_db();
ac0630a2
RB
1781 }
1782
1783 if (!ovnnb_db) {
1784 ovnnb_db = default_db();
1785 }
1786
1787 free(short_options);
1788}
1789
5868eb24
BP
1790static void
1791add_column_noalert(struct ovsdb_idl *idl,
1792 const struct ovsdb_idl_column *column)
1793{
1794 ovsdb_idl_add_column(idl, column);
1795 ovsdb_idl_omit_alert(idl, column);
1796}
1797
ac0630a2
RB
1798int
1799main(int argc, char *argv[])
1800{
1801 extern struct vlog_module VLM_reconnect;
f20396e0 1802 unsigned int ovnnb_seqno, ovnsb_seqno;
ac0630a2 1803 int res = EXIT_SUCCESS;
7b303ff9
AW
1804 struct unixctl_server *unixctl;
1805 int retval;
1806 bool exiting;
ac0630a2
RB
1807
1808 fatal_ignore_sigpipe();
1809 set_program_name(argv[0]);
485f0696 1810 service_start(&argc, &argv);
ac0630a2
RB
1811 vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
1812 vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
1813 parse_options(argc, argv);
67d9b930 1814
e91b927d 1815 daemonize_start(false);
7b303ff9
AW
1816
1817 retval = unixctl_server_create(NULL, &unixctl);
1818 if (retval) {
1819 exit(EXIT_FAILURE);
1820 }
1821 unixctl_command_register("exit", "", 0, 0, ovn_northd_exit, &exiting);
1822
1823 daemonize_complete();
67d9b930 1824
ac0630a2 1825 nbrec_init();
ec78987f 1826 sbrec_init();
ac0630a2
RB
1827
1828 /* We want to detect all changes to the ovn-nb db. */
331e7aef
NS
1829 struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
1830 ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, true, true));
1831
1832 struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
1833 ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true));
1834
1835 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_logical_flow);
1836 add_column_noalert(ovnsb_idl_loop.idl,
1837 &sbrec_logical_flow_col_logical_datapath);
1838 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_pipeline);
1839 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_table_id);
1840 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_priority);
1841 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match);
1842 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_actions);
1843
1844 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_multicast_group);
1845 add_column_noalert(ovnsb_idl_loop.idl,
1846 &sbrec_multicast_group_col_datapath);
1847 add_column_noalert(ovnsb_idl_loop.idl,
1848 &sbrec_multicast_group_col_tunnel_key);
1849 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_name);
1850 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_ports);
1851
1852 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding);
1853 add_column_noalert(ovnsb_idl_loop.idl,
1854 &sbrec_datapath_binding_col_tunnel_key);
1855 add_column_noalert(ovnsb_idl_loop.idl,
1856 &sbrec_datapath_binding_col_external_ids);
1857
1858 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding);
1859 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_datapath);
1860 add_column_noalert(ovnsb_idl_loop.idl,
1861 &sbrec_port_binding_col_logical_port);
1862 add_column_noalert(ovnsb_idl_loop.idl,
1863 &sbrec_port_binding_col_tunnel_key);
1864 add_column_noalert(ovnsb_idl_loop.idl,
1865 &sbrec_port_binding_col_parent_port);
1866 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_tag);
1867 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_type);
1868 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_options);
1869 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac);
1870 ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis);
1871
f20396e0
JS
1872 ovnnb_seqno = ovsdb_idl_get_seqno(ovnnb_idl_loop.idl);
1873 ovnsb_seqno = ovsdb_idl_get_seqno(ovnsb_idl_loop.idl);
1874
331e7aef 1875 /* Main loop. */
7b303ff9
AW
1876 exiting = false;
1877 while (!exiting) {
331e7aef
NS
1878 struct northd_context ctx = {
1879 .ovnnb_idl = ovnnb_idl_loop.idl,
1880 .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop),
1881 .ovnsb_idl = ovnsb_idl_loop.idl,
1882 .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
1883 };
ac0630a2 1884
f20396e0
JS
1885 if (ovnnb_seqno != ovsdb_idl_get_seqno(ctx.ovnnb_idl)) {
1886 ovnnb_seqno = ovsdb_idl_get_seqno(ctx.ovnnb_idl);
1887 ovnnb_db_run(&ctx);
1888 }
1889 if (ovnsb_seqno != ovsdb_idl_get_seqno(ctx.ovnsb_idl)) {
1890 ovnsb_seqno = ovsdb_idl_get_seqno(ctx.ovnsb_idl);
1891 ovnsb_db_run(&ctx);
1892 }
f93818dd 1893
331e7aef
NS
1894 unixctl_server_run(unixctl);
1895 unixctl_server_wait(unixctl);
1896 if (exiting) {
1897 poll_immediate_wake();
ac0630a2 1898 }
331e7aef
NS
1899 ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);
1900 ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
ac0630a2 1901
331e7aef 1902 poll_block();
485f0696
GS
1903 if (should_service_stop()) {
1904 exiting = true;
1905 }
ac0630a2
RB
1906 }
1907
7b303ff9 1908 unixctl_server_destroy(unixctl);
331e7aef
NS
1909 ovsdb_idl_loop_destroy(&ovnnb_idl_loop);
1910 ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
485f0696 1911 service_stop();
ac0630a2 1912
45f98d4c 1913 free(default_db_);
ac0630a2
RB
1914 exit(res);
1915}
7b303ff9
AW
1916
1917static void
1918ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
1919 const char *argv[] OVS_UNUSED, void *exiting_)
1920{
1921 bool *exiting = exiting_;
1922 *exiting = true;
1923
1924 unixctl_command_reply(conn, NULL);
1925}