]> git.proxmox.com Git - mirror_ovs.git/blame - ovn/northd/ovn-northd.c
Move lib/match.h to include/openvswitch directory
[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"
3e8a2ad1 24#include "openvswitch/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 54
60bdd011
RM
55static const char *default_nb_db(void);
56static const char *default_sb_db(void);
880fcd14
BP
57\f
58/* Pipeline stages. */
ac0630a2 59
880fcd14
BP
60/* The two pipelines in an OVN logical flow table. */
61enum ovn_pipeline {
62 P_IN, /* Ingress pipeline. */
63 P_OUT /* Egress pipeline. */
64};
091e3af9 65
880fcd14
BP
66/* The two purposes for which ovn-northd uses OVN logical datapaths. */
67enum ovn_datapath_type {
68 DP_SWITCH, /* OVN logical switch. */
69 DP_ROUTER /* OVN logical router. */
091e3af9
JP
70};
71
880fcd14
BP
72/* Returns an "enum ovn_stage" built from the arguments.
73 *
74 * (It's better to use ovn_stage_build() for type-safety reasons, but inline
75 * functions can't be used in enums or switch cases.) */
76#define OVN_STAGE_BUILD(DP_TYPE, PIPELINE, TABLE) \
77 (((DP_TYPE) << 9) | ((PIPELINE) << 8) | (TABLE))
78
79/* A stage within an OVN logical switch or router.
091e3af9 80 *
880fcd14
BP
81 * An "enum ovn_stage" indicates whether the stage is part of a logical switch
82 * or router, whether the stage is part of the ingress or egress pipeline, and
83 * the table within that pipeline. The first three components are combined to
685f4dfe 84 * form the stage's full name, e.g. S_SWITCH_IN_PORT_SEC_L2,
880fcd14
BP
85 * S_ROUTER_OUT_DELIVERY. */
86enum ovn_stage {
e0c9e58b
JP
87#define PIPELINE_STAGES \
88 /* Logical switch ingress stages. */ \
685f4dfe
NS
89 PIPELINE_STAGE(SWITCH, IN, PORT_SEC_L2, 0, "ls_in_port_sec_l2") \
90 PIPELINE_STAGE(SWITCH, IN, PORT_SEC_IP, 1, "ls_in_port_sec_ip") \
91 PIPELINE_STAGE(SWITCH, IN, PORT_SEC_ND, 2, "ls_in_port_sec_nd") \
92 PIPELINE_STAGE(SWITCH, IN, PRE_ACL, 3, "ls_in_pre_acl") \
93 PIPELINE_STAGE(SWITCH, IN, ACL, 4, "ls_in_acl") \
94 PIPELINE_STAGE(SWITCH, IN, ARP_RSP, 5, "ls_in_arp_rsp") \
95 PIPELINE_STAGE(SWITCH, IN, L2_LKUP, 6, "ls_in_l2_lkup") \
e0c9e58b
JP
96 \
97 /* Logical switch egress stages. */ \
98 PIPELINE_STAGE(SWITCH, OUT, PRE_ACL, 0, "ls_out_pre_acl") \
99 PIPELINE_STAGE(SWITCH, OUT, ACL, 1, "ls_out_acl") \
685f4dfe
NS
100 PIPELINE_STAGE(SWITCH, OUT, PORT_SEC_IP, 2, "ls_out_port_sec_ip") \
101 PIPELINE_STAGE(SWITCH, OUT, PORT_SEC_L2, 3, "ls_out_port_sec_l2") \
e0c9e58b
JP
102 \
103 /* Logical router ingress stages. */ \
104 PIPELINE_STAGE(ROUTER, IN, ADMISSION, 0, "lr_in_admission") \
105 PIPELINE_STAGE(ROUTER, IN, IP_INPUT, 1, "lr_in_ip_input") \
106 PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 2, "lr_in_ip_routing") \
0bac7164
BP
107 PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 3, "lr_in_arp_resolve") \
108 PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 4, "lr_in_arp_request") \
e0c9e58b
JP
109 \
110 /* Logical router egress stages. */ \
111 PIPELINE_STAGE(ROUTER, OUT, DELIVERY, 0, "lr_out_delivery")
880fcd14
BP
112
113#define PIPELINE_STAGE(DP_TYPE, PIPELINE, STAGE, TABLE, NAME) \
114 S_##DP_TYPE##_##PIPELINE##_##STAGE \
115 = OVN_STAGE_BUILD(DP_##DP_TYPE, P_##PIPELINE, TABLE),
116 PIPELINE_STAGES
117#undef PIPELINE_STAGE
091e3af9
JP
118};
119
6bb4a18e
JP
120/* Due to various hard-coded priorities need to implement ACLs, the
121 * northbound database supports a smaller range of ACL priorities than
122 * are available to logical flows. This value is added to an ACL
123 * priority to determine the ACL's logical flow priority. */
124#define OVN_ACL_PRI_OFFSET 1000
125
880fcd14
BP
126/* Returns an "enum ovn_stage" built from the arguments. */
127static enum ovn_stage
128ovn_stage_build(enum ovn_datapath_type dp_type, enum ovn_pipeline pipeline,
129 uint8_t table)
130{
131 return OVN_STAGE_BUILD(dp_type, pipeline, table);
132}
133
134/* Returns the pipeline to which 'stage' belongs. */
135static enum ovn_pipeline
136ovn_stage_get_pipeline(enum ovn_stage stage)
137{
138 return (stage >> 8) & 1;
139}
140
141/* Returns the table to which 'stage' belongs. */
142static uint8_t
143ovn_stage_get_table(enum ovn_stage stage)
144{
145 return stage & 0xff;
146}
147
148/* Returns a string name for 'stage'. */
149static const char *
150ovn_stage_to_str(enum ovn_stage stage)
151{
152 switch (stage) {
153#define PIPELINE_STAGE(DP_TYPE, PIPELINE, STAGE, TABLE, NAME) \
154 case S_##DP_TYPE##_##PIPELINE##_##STAGE: return NAME;
155 PIPELINE_STAGES
156#undef PIPELINE_STAGE
157 default: return "<unknown>";
158 }
159}
160\f
ac0630a2
RB
161static void
162usage(void)
163{
164 printf("\
165%s: OVN northbound management daemon\n\
166usage: %s [OPTIONS]\n\
167\n\
168Options:\n\
169 --ovnnb-db=DATABASE connect to ovn-nb database at DATABASE\n\
170 (default: %s)\n\
ec78987f 171 --ovnsb-db=DATABASE connect to ovn-sb database at DATABASE\n\
ac0630a2
RB
172 (default: %s)\n\
173 -h, --help display this help message\n\
174 -o, --options list available options\n\
175 -V, --version display version information\n\
60bdd011 176", program_name, program_name, default_nb_db(), default_sb_db());
67d9b930 177 daemon_usage();
ac0630a2
RB
178 vlog_usage();
179 stream_usage("database", true, true, false);
180}
181\f
5868eb24
BP
182struct tnlid_node {
183 struct hmap_node hmap_node;
184 uint32_t tnlid;
185};
186
187static void
188destroy_tnlids(struct hmap *tnlids)
4edcdcf4 189{
5868eb24
BP
190 struct tnlid_node *node, *next;
191 HMAP_FOR_EACH_SAFE (node, next, hmap_node, tnlids) {
192 hmap_remove(tnlids, &node->hmap_node);
193 free(node);
194 }
195 hmap_destroy(tnlids);
196}
197
198static void
199add_tnlid(struct hmap *set, uint32_t tnlid)
200{
201 struct tnlid_node *node = xmalloc(sizeof *node);
202 hmap_insert(set, &node->hmap_node, hash_int(tnlid, 0));
203 node->tnlid = tnlid;
4edcdcf4
RB
204}
205
4edcdcf4 206static bool
5868eb24 207tnlid_in_use(const struct hmap *set, uint32_t tnlid)
4edcdcf4 208{
5868eb24
BP
209 const struct tnlid_node *node;
210 HMAP_FOR_EACH_IN_BUCKET (node, hmap_node, hash_int(tnlid, 0), set) {
211 if (node->tnlid == tnlid) {
212 return true;
213 }
214 }
215 return false;
216}
4edcdcf4 217
5868eb24
BP
218static uint32_t
219allocate_tnlid(struct hmap *set, const char *name, uint32_t max,
220 uint32_t *hint)
221{
222 for (uint32_t tnlid = *hint + 1; tnlid != *hint;
223 tnlid = tnlid + 1 <= max ? tnlid + 1 : 1) {
224 if (!tnlid_in_use(set, tnlid)) {
225 add_tnlid(set, tnlid);
226 *hint = tnlid;
227 return tnlid;
228 }
4edcdcf4
RB
229 }
230
5868eb24
BP
231 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
232 VLOG_WARN_RL(&rl, "all %s tunnel ids exhausted", name);
233 return 0;
234}
235\f
9975d7be
BP
236/* The 'key' comes from nbs->header_.uuid or nbr->header_.uuid or
237 * sb->external_ids:logical-switch. */
5868eb24
BP
238struct ovn_datapath {
239 struct hmap_node key_node; /* Index on 'key'. */
9975d7be 240 struct uuid key; /* (nbs/nbr)->header_.uuid. */
4edcdcf4 241
9975d7be
BP
242 const struct nbrec_logical_switch *nbs; /* May be NULL. */
243 const struct nbrec_logical_router *nbr; /* May be NULL. */
5868eb24 244 const struct sbrec_datapath_binding *sb; /* May be NULL. */
4edcdcf4 245
5868eb24 246 struct ovs_list list; /* In list of similar records. */
4edcdcf4 247
9975d7be 248 /* Logical router data (digested from nbr). */
0bac7164 249 const struct ovn_port *gateway_port;
9975d7be
BP
250 ovs_be32 gateway;
251
252 /* Logical switch data. */
86e98048
BP
253 struct ovn_port **router_ports;
254 size_t n_router_ports;
9975d7be 255
5868eb24
BP
256 struct hmap port_tnlids;
257 uint32_t port_key_hint;
258
259 bool has_unknown;
260};
261
262static struct ovn_datapath *
263ovn_datapath_create(struct hmap *datapaths, const struct uuid *key,
9975d7be
BP
264 const struct nbrec_logical_switch *nbs,
265 const struct nbrec_logical_router *nbr,
5868eb24
BP
266 const struct sbrec_datapath_binding *sb)
267{
268 struct ovn_datapath *od = xzalloc(sizeof *od);
269 od->key = *key;
270 od->sb = sb;
9975d7be
BP
271 od->nbs = nbs;
272 od->nbr = nbr;
5868eb24
BP
273 hmap_init(&od->port_tnlids);
274 od->port_key_hint = 0;
275 hmap_insert(datapaths, &od->key_node, uuid_hash(&od->key));
276 return od;
277}
278
279static void
280ovn_datapath_destroy(struct hmap *datapaths, struct ovn_datapath *od)
281{
282 if (od) {
283 /* Don't remove od->list. It is used within build_datapaths() as a
284 * private list and once we've exited that function it is not safe to
285 * use it. */
286 hmap_remove(datapaths, &od->key_node);
287 destroy_tnlids(&od->port_tnlids);
86e98048 288 free(od->router_ports);
5868eb24
BP
289 free(od);
290 }
291}
292
293static struct ovn_datapath *
294ovn_datapath_find(struct hmap *datapaths, const struct uuid *uuid)
295{
296 struct ovn_datapath *od;
297
298 HMAP_FOR_EACH_WITH_HASH (od, key_node, uuid_hash(uuid), datapaths) {
299 if (uuid_equals(uuid, &od->key)) {
300 return od;
301 }
302 }
303 return NULL;
304}
305
306static struct ovn_datapath *
307ovn_datapath_from_sbrec(struct hmap *datapaths,
308 const struct sbrec_datapath_binding *sb)
309{
310 struct uuid key;
311
9975d7be
BP
312 if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) &&
313 !smap_get_uuid(&sb->external_ids, "logical-router", &key)) {
5868eb24
BP
314 return NULL;
315 }
316 return ovn_datapath_find(datapaths, &key);
317}
318
319static void
320join_datapaths(struct northd_context *ctx, struct hmap *datapaths,
321 struct ovs_list *sb_only, struct ovs_list *nb_only,
322 struct ovs_list *both)
323{
324 hmap_init(datapaths);
417e7e66
BW
325 ovs_list_init(sb_only);
326 ovs_list_init(nb_only);
327 ovs_list_init(both);
5868eb24
BP
328
329 const struct sbrec_datapath_binding *sb, *sb_next;
330 SBREC_DATAPATH_BINDING_FOR_EACH_SAFE (sb, sb_next, ctx->ovnsb_idl) {
331 struct uuid key;
9975d7be
BP
332 if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) &&
333 !smap_get_uuid(&sb->external_ids, "logical-router", &key)) {
334 ovsdb_idl_txn_add_comment(
335 ctx->ovnsb_txn,
336 "deleting Datapath_Binding "UUID_FMT" that lacks "
337 "external-ids:logical-switch and "
338 "external-ids:logical-router",
339 UUID_ARGS(&sb->header_.uuid));
5868eb24
BP
340 sbrec_datapath_binding_delete(sb);
341 continue;
342 }
343
344 if (ovn_datapath_find(datapaths, &key)) {
345 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
9975d7be
BP
346 VLOG_INFO_RL(
347 &rl, "deleting Datapath_Binding "UUID_FMT" with "
348 "duplicate external-ids:logical-switch/router "UUID_FMT,
349 UUID_ARGS(&sb->header_.uuid), UUID_ARGS(&key));
5868eb24
BP
350 sbrec_datapath_binding_delete(sb);
351 continue;
352 }
353
354 struct ovn_datapath *od = ovn_datapath_create(datapaths, &key,
9975d7be 355 NULL, NULL, sb);
417e7e66 356 ovs_list_push_back(sb_only, &od->list);
5868eb24
BP
357 }
358
9975d7be
BP
359 const struct nbrec_logical_switch *nbs;
360 NBREC_LOGICAL_SWITCH_FOR_EACH (nbs, ctx->ovnnb_idl) {
5868eb24 361 struct ovn_datapath *od = ovn_datapath_find(datapaths,
9975d7be 362 &nbs->header_.uuid);
5868eb24 363 if (od) {
9975d7be 364 od->nbs = nbs;
417e7e66
BW
365 ovs_list_remove(&od->list);
366 ovs_list_push_back(both, &od->list);
5868eb24 367 } else {
9975d7be
BP
368 od = ovn_datapath_create(datapaths, &nbs->header_.uuid,
369 nbs, NULL, NULL);
417e7e66 370 ovs_list_push_back(nb_only, &od->list);
5868eb24
BP
371 }
372 }
9975d7be
BP
373
374 const struct nbrec_logical_router *nbr;
375 NBREC_LOGICAL_ROUTER_FOR_EACH (nbr, ctx->ovnnb_idl) {
376 struct ovn_datapath *od = ovn_datapath_find(datapaths,
377 &nbr->header_.uuid);
378 if (od) {
379 if (!od->nbs) {
380 od->nbr = nbr;
417e7e66
BW
381 ovs_list_remove(&od->list);
382 ovs_list_push_back(both, &od->list);
9975d7be
BP
383 } else {
384 /* Can't happen! */
385 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
386 VLOG_WARN_RL(&rl,
387 "duplicate UUID "UUID_FMT" in OVN_Northbound",
388 UUID_ARGS(&nbr->header_.uuid));
389 continue;
390 }
391 } else {
392 od = ovn_datapath_create(datapaths, &nbr->header_.uuid,
393 NULL, nbr, NULL);
417e7e66 394 ovs_list_push_back(nb_only, &od->list);
9975d7be
BP
395 }
396
397 od->gateway = 0;
398 if (nbr->default_gw) {
0bac7164
BP
399 ovs_be32 ip;
400 if (!ip_parse(nbr->default_gw, &ip) || !ip) {
401 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
9975d7be 402 VLOG_WARN_RL(&rl, "bad 'gateway' %s", nbr->default_gw);
9975d7be
BP
403 } else {
404 od->gateway = ip;
405 }
406 }
0bac7164
BP
407
408 /* Set the gateway port to NULL. If there is a gateway, it will get
409 * filled in as we go through the ports later. */
410 od->gateway_port = NULL;
9975d7be 411 }
5868eb24
BP
412}
413
414static uint32_t
415ovn_datapath_allocate_key(struct hmap *dp_tnlids)
416{
417 static uint32_t hint;
418 return allocate_tnlid(dp_tnlids, "datapath", (1u << 24) - 1, &hint);
419}
420
0bac7164
BP
421/* Updates the southbound Datapath_Binding table so that it contains the
422 * logical switches and routers specified by the northbound database.
423 *
424 * Initializes 'datapaths' to contain a "struct ovn_datapath" for every logical
425 * switch and router. */
5868eb24
BP
426static void
427build_datapaths(struct northd_context *ctx, struct hmap *datapaths)
428{
429 struct ovs_list sb_only, nb_only, both;
430
431 join_datapaths(ctx, datapaths, &sb_only, &nb_only, &both);
432
417e7e66 433 if (!ovs_list_is_empty(&nb_only)) {
5868eb24
BP
434 /* First index the in-use datapath tunnel IDs. */
435 struct hmap dp_tnlids = HMAP_INITIALIZER(&dp_tnlids);
436 struct ovn_datapath *od;
437 LIST_FOR_EACH (od, list, &both) {
438 add_tnlid(&dp_tnlids, od->sb->tunnel_key);
439 }
440
441 /* Add southbound record for each unmatched northbound record. */
442 LIST_FOR_EACH (od, list, &nb_only) {
443 uint16_t tunnel_key = ovn_datapath_allocate_key(&dp_tnlids);
444 if (!tunnel_key) {
445 break;
446 }
447
448 od->sb = sbrec_datapath_binding_insert(ctx->ovnsb_txn);
449
5868eb24 450 char uuid_s[UUID_LEN + 1];
9975d7be
BP
451 sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->key));
452 const char *key = od->nbs ? "logical-switch" : "logical-router";
453 const struct smap id = SMAP_CONST1(&id, key, uuid_s);
aaf881c6 454 sbrec_datapath_binding_set_external_ids(od->sb, &id);
5868eb24
BP
455
456 sbrec_datapath_binding_set_tunnel_key(od->sb, tunnel_key);
457 }
458 destroy_tnlids(&dp_tnlids);
459 }
460
461 /* Delete southbound records without northbound matches. */
462 struct ovn_datapath *od, *next;
463 LIST_FOR_EACH_SAFE (od, next, list, &sb_only) {
417e7e66 464 ovs_list_remove(&od->list);
5868eb24
BP
465 sbrec_datapath_binding_delete(od->sb);
466 ovn_datapath_destroy(datapaths, od);
467 }
468}
469\f
470struct ovn_port {
471 struct hmap_node key_node; /* Index on 'key'. */
9975d7be
BP
472 char *key; /* nbs->name, nbr->name, sb->logical_port. */
473 char *json_key; /* 'key', quoted for use in JSON. */
5868eb24 474
9975d7be
BP
475 const struct nbrec_logical_port *nbs; /* May be NULL. */
476 const struct nbrec_logical_router_port *nbr; /* May be NULL. */
477 const struct sbrec_port_binding *sb; /* May be NULL. */
478
479 /* Logical router port data. */
480 ovs_be32 ip, mask; /* 192.168.10.123/24. */
481 ovs_be32 network; /* 192.168.10.0. */
482 ovs_be32 bcast; /* 192.168.10.255. */
483 struct eth_addr mac;
484 struct ovn_port *peer;
5868eb24
BP
485
486 struct ovn_datapath *od;
487
488 struct ovs_list list; /* In list of similar records. */
489};
490
491static struct ovn_port *
492ovn_port_create(struct hmap *ports, const char *key,
9975d7be
BP
493 const struct nbrec_logical_port *nbs,
494 const struct nbrec_logical_router_port *nbr,
5868eb24
BP
495 const struct sbrec_port_binding *sb)
496{
497 struct ovn_port *op = xzalloc(sizeof *op);
9975d7be
BP
498
499 struct ds json_key = DS_EMPTY_INITIALIZER;
500 json_string_escape(key, &json_key);
501 op->json_key = ds_steal_cstr(&json_key);
502
503 op->key = xstrdup(key);
5868eb24 504 op->sb = sb;
9975d7be
BP
505 op->nbs = nbs;
506 op->nbr = nbr;
5868eb24
BP
507 hmap_insert(ports, &op->key_node, hash_string(op->key, 0));
508 return op;
509}
510
511static void
512ovn_port_destroy(struct hmap *ports, struct ovn_port *port)
513{
514 if (port) {
515 /* Don't remove port->list. It is used within build_ports() as a
516 * private list and once we've exited that function it is not safe to
517 * use it. */
518 hmap_remove(ports, &port->key_node);
9975d7be
BP
519 free(port->json_key);
520 free(port->key);
5868eb24
BP
521 free(port);
522 }
523}
524
525static struct ovn_port *
526ovn_port_find(struct hmap *ports, const char *name)
527{
528 struct ovn_port *op;
529
530 HMAP_FOR_EACH_WITH_HASH (op, key_node, hash_string(name, 0), ports) {
531 if (!strcmp(op->key, name)) {
532 return op;
533 }
534 }
535 return NULL;
536}
537
538static uint32_t
539ovn_port_allocate_key(struct ovn_datapath *od)
540{
541 return allocate_tnlid(&od->port_tnlids, "port",
542 (1u << 15) - 1, &od->port_key_hint);
543}
544
545static void
546join_logical_ports(struct northd_context *ctx,
547 struct hmap *datapaths, struct hmap *ports,
548 struct ovs_list *sb_only, struct ovs_list *nb_only,
549 struct ovs_list *both)
550{
551 hmap_init(ports);
417e7e66
BW
552 ovs_list_init(sb_only);
553 ovs_list_init(nb_only);
554 ovs_list_init(both);
5868eb24
BP
555
556 const struct sbrec_port_binding *sb;
557 SBREC_PORT_BINDING_FOR_EACH (sb, ctx->ovnsb_idl) {
558 struct ovn_port *op = ovn_port_create(ports, sb->logical_port,
9975d7be 559 NULL, NULL, sb);
417e7e66 560 ovs_list_push_back(sb_only, &op->list);
5868eb24
BP
561 }
562
563 struct ovn_datapath *od;
564 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
565 if (od->nbs) {
566 for (size_t i = 0; i < od->nbs->n_ports; i++) {
567 const struct nbrec_logical_port *nbs = od->nbs->ports[i];
568 struct ovn_port *op = ovn_port_find(ports, nbs->name);
569 if (op) {
570 if (op->nbs || op->nbr) {
571 static struct vlog_rate_limit rl
572 = VLOG_RATE_LIMIT_INIT(5, 1);
573 VLOG_WARN_RL(&rl, "duplicate logical port %s",
574 nbs->name);
575 continue;
576 }
577 op->nbs = nbs;
417e7e66
BW
578 ovs_list_remove(&op->list);
579 ovs_list_push_back(both, &op->list);
9975d7be
BP
580 } else {
581 op = ovn_port_create(ports, nbs->name, nbs, NULL, NULL);
417e7e66 582 ovs_list_push_back(nb_only, &op->list);
9975d7be
BP
583 }
584
585 op->od = od;
586 }
587 } else {
588 for (size_t i = 0; i < od->nbr->n_ports; i++) {
589 const struct nbrec_logical_router_port *nbr
590 = od->nbr->ports[i];
591
592 struct eth_addr mac;
593 if (!eth_addr_from_string(nbr->mac, &mac)) {
594 static struct vlog_rate_limit rl
595 = VLOG_RATE_LIMIT_INIT(5, 1);
596 VLOG_WARN_RL(&rl, "bad 'mac' %s", nbr->mac);
597 continue;
598 }
599
600 ovs_be32 ip, mask;
601 char *error = ip_parse_masked(nbr->network, &ip, &mask);
602 if (error || mask == OVS_BE32_MAX || !ip_is_cidr(mask)) {
603 static struct vlog_rate_limit rl
604 = VLOG_RATE_LIMIT_INIT(5, 1);
605 VLOG_WARN_RL(&rl, "bad 'network' %s", nbr->network);
606 free(error);
607 continue;
608 }
609
00007447 610 struct ovn_port *op = ovn_port_find(ports, nbr->name);
9975d7be
BP
611 if (op) {
612 if (op->nbs || op->nbr) {
613 static struct vlog_rate_limit rl
614 = VLOG_RATE_LIMIT_INIT(5, 1);
615 VLOG_WARN_RL(&rl, "duplicate logical router port %s",
00007447 616 nbr->name);
9975d7be
BP
617 continue;
618 }
619 op->nbr = nbr;
417e7e66
BW
620 ovs_list_remove(&op->list);
621 ovs_list_push_back(both, &op->list);
9975d7be 622 } else {
00007447 623 op = ovn_port_create(ports, nbr->name, NULL, nbr, NULL);
417e7e66 624 ovs_list_push_back(nb_only, &op->list);
9975d7be
BP
625 }
626
627 op->ip = ip;
628 op->mask = mask;
629 op->network = ip & mask;
630 op->bcast = ip | ~mask;
631 op->mac = mac;
632
633 op->od = od;
0bac7164
BP
634
635 /* If 'od' has a gateway and 'op' routes to it... */
636 if (od->gateway && !((op->network ^ od->gateway) & op->mask)) {
637 /* ...and if 'op' is a longer match than the current
638 * choice... */
639 const struct ovn_port *gw = od->gateway_port;
640 int len = gw ? ip_count_cidr_bits(gw->mask) : 0;
641 if (ip_count_cidr_bits(op->mask) > len) {
642 /* ...then it's the default gateway port. */
643 od->gateway_port = op;
644 }
645 }
5868eb24 646 }
9975d7be
BP
647 }
648 }
649
650 /* Connect logical router ports, and logical switch ports of type "router",
651 * to their peers. */
652 struct ovn_port *op;
653 HMAP_FOR_EACH (op, key_node, ports) {
654 if (op->nbs && !strcmp(op->nbs->type, "router")) {
655 const char *peer_name = smap_get(&op->nbs->options, "router-port");
656 if (!peer_name) {
657 continue;
658 }
659
660 struct ovn_port *peer = ovn_port_find(ports, peer_name);
661 if (!peer || !peer->nbr) {
662 continue;
663 }
664
665 peer->peer = op;
666 op->peer = peer;
86e98048
BP
667 op->od->router_ports = xrealloc(
668 op->od->router_ports,
669 sizeof *op->od->router_ports * (op->od->n_router_ports + 1));
670 op->od->router_ports[op->od->n_router_ports++] = op;
9975d7be 671 } else if (op->nbr && op->nbr->peer) {
509afdc3 672 op->peer = ovn_port_find(ports, op->nbr->peer);
5868eb24
BP
673 }
674 }
675}
676
677static void
678ovn_port_update_sbrec(const struct ovn_port *op)
679{
680 sbrec_port_binding_set_datapath(op->sb, op->od->sb);
9975d7be
BP
681 if (op->nbr) {
682 sbrec_port_binding_set_type(op->sb, "patch");
683
684 const char *peer = op->peer ? op->peer->key : "<error>";
685 const struct smap ids = SMAP_CONST1(&ids, "peer", peer);
686 sbrec_port_binding_set_options(op->sb, &ids);
687
688 sbrec_port_binding_set_parent_port(op->sb, NULL);
689 sbrec_port_binding_set_tag(op->sb, NULL, 0);
690 sbrec_port_binding_set_mac(op->sb, NULL, 0);
691 } else {
692 if (strcmp(op->nbs->type, "router")) {
693 sbrec_port_binding_set_type(op->sb, op->nbs->type);
694 sbrec_port_binding_set_options(op->sb, &op->nbs->options);
695 } else {
696 sbrec_port_binding_set_type(op->sb, "patch");
697
698 const char *router_port = smap_get(&op->nbs->options,
699 "router-port");
700 if (!router_port) {
701 router_port = "<error>";
702 }
703 const struct smap ids = SMAP_CONST1(&ids, "peer", router_port);
704 sbrec_port_binding_set_options(op->sb, &ids);
705 }
706 sbrec_port_binding_set_parent_port(op->sb, op->nbs->parent_name);
707 sbrec_port_binding_set_tag(op->sb, op->nbs->tag, op->nbs->n_tag);
708 sbrec_port_binding_set_mac(op->sb, (const char **) op->nbs->addresses,
709 op->nbs->n_addresses);
710 }
5868eb24
BP
711}
712
0bac7164
BP
713/* Updates the southbound Port_Binding table so that it contains the logical
714 * ports specified by the northbound database.
715 *
716 * Initializes 'ports' to contain a "struct ovn_port" for every logical port,
717 * using the "struct ovn_datapath"s in 'datapaths' to look up logical
718 * datapaths. */
5868eb24
BP
719static void
720build_ports(struct northd_context *ctx, struct hmap *datapaths,
721 struct hmap *ports)
722{
723 struct ovs_list sb_only, nb_only, both;
724
725 join_logical_ports(ctx, datapaths, ports, &sb_only, &nb_only, &both);
726
727 /* For logical ports that are in both databases, update the southbound
728 * record based on northbound data. Also index the in-use tunnel_keys. */
729 struct ovn_port *op, *next;
730 LIST_FOR_EACH_SAFE (op, next, list, &both) {
731 ovn_port_update_sbrec(op);
732
733 add_tnlid(&op->od->port_tnlids, op->sb->tunnel_key);
734 if (op->sb->tunnel_key > op->od->port_key_hint) {
735 op->od->port_key_hint = op->sb->tunnel_key;
736 }
737 }
738
739 /* Add southbound record for each unmatched northbound record. */
740 LIST_FOR_EACH_SAFE (op, next, list, &nb_only) {
741 uint16_t tunnel_key = ovn_port_allocate_key(op->od);
742 if (!tunnel_key) {
743 continue;
744 }
745
746 op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn);
747 ovn_port_update_sbrec(op);
748
749 sbrec_port_binding_set_logical_port(op->sb, op->key);
750 sbrec_port_binding_set_tunnel_key(op->sb, tunnel_key);
751 }
752
753 /* Delete southbound records without northbound matches. */
754 LIST_FOR_EACH_SAFE(op, next, list, &sb_only) {
417e7e66 755 ovs_list_remove(&op->list);
5868eb24
BP
756 sbrec_port_binding_delete(op->sb);
757 ovn_port_destroy(ports, op);
758 }
759}
760\f
761#define OVN_MIN_MULTICAST 32768
762#define OVN_MAX_MULTICAST 65535
763
764struct multicast_group {
765 const char *name;
766 uint16_t key; /* OVN_MIN_MULTICAST...OVN_MAX_MULTICAST. */
767};
768
769#define MC_FLOOD "_MC_flood"
770static const struct multicast_group mc_flood = { MC_FLOOD, 65535 };
771
772#define MC_UNKNOWN "_MC_unknown"
773static const struct multicast_group mc_unknown = { MC_UNKNOWN, 65534 };
774
775static bool
776multicast_group_equal(const struct multicast_group *a,
777 const struct multicast_group *b)
778{
779 return !strcmp(a->name, b->name) && a->key == b->key;
780}
781
782/* Multicast group entry. */
783struct ovn_multicast {
784 struct hmap_node hmap_node; /* Index on 'datapath' and 'key'. */
785 struct ovn_datapath *datapath;
786 const struct multicast_group *group;
787
788 struct ovn_port **ports;
789 size_t n_ports, allocated_ports;
790};
791
792static uint32_t
793ovn_multicast_hash(const struct ovn_datapath *datapath,
794 const struct multicast_group *group)
795{
796 return hash_pointer(datapath, group->key);
797}
798
799static struct ovn_multicast *
800ovn_multicast_find(struct hmap *mcgroups, struct ovn_datapath *datapath,
801 const struct multicast_group *group)
802{
803 struct ovn_multicast *mc;
804
805 HMAP_FOR_EACH_WITH_HASH (mc, hmap_node,
806 ovn_multicast_hash(datapath, group), mcgroups) {
807 if (mc->datapath == datapath
808 && multicast_group_equal(mc->group, group)) {
809 return mc;
4edcdcf4
RB
810 }
811 }
5868eb24
BP
812 return NULL;
813}
814
815static void
816ovn_multicast_add(struct hmap *mcgroups, const struct multicast_group *group,
817 struct ovn_port *port)
818{
819 struct ovn_datapath *od = port->od;
820 struct ovn_multicast *mc = ovn_multicast_find(mcgroups, od, group);
821 if (!mc) {
822 mc = xmalloc(sizeof *mc);
823 hmap_insert(mcgroups, &mc->hmap_node, ovn_multicast_hash(od, group));
824 mc->datapath = od;
825 mc->group = group;
826 mc->n_ports = 0;
827 mc->allocated_ports = 4;
828 mc->ports = xmalloc(mc->allocated_ports * sizeof *mc->ports);
829 }
830 if (mc->n_ports >= mc->allocated_ports) {
831 mc->ports = x2nrealloc(mc->ports, &mc->allocated_ports,
832 sizeof *mc->ports);
833 }
834 mc->ports[mc->n_ports++] = port;
835}
4edcdcf4 836
5868eb24
BP
837static void
838ovn_multicast_destroy(struct hmap *mcgroups, struct ovn_multicast *mc)
839{
840 if (mc) {
841 hmap_remove(mcgroups, &mc->hmap_node);
842 free(mc->ports);
843 free(mc);
844 }
845}
4edcdcf4 846
5868eb24
BP
847static void
848ovn_multicast_update_sbrec(const struct ovn_multicast *mc,
849 const struct sbrec_multicast_group *sb)
850{
851 struct sbrec_port_binding **ports = xmalloc(mc->n_ports * sizeof *ports);
852 for (size_t i = 0; i < mc->n_ports; i++) {
853 ports[i] = CONST_CAST(struct sbrec_port_binding *, mc->ports[i]->sb);
854 }
855 sbrec_multicast_group_set_ports(sb, ports, mc->n_ports);
856 free(ports);
4edcdcf4 857}
bd39395f 858\f
48605550 859/* Logical flow generation.
bd39395f 860 *
48605550 861 * This code generates the Logical_Flow table in the southbound database, as a
bd39395f
BP
862 * function of most of the northbound database.
863 */
864
5868eb24
BP
865struct ovn_lflow {
866 struct hmap_node hmap_node;
bd39395f 867
5868eb24 868 struct ovn_datapath *od;
880fcd14 869 enum ovn_stage stage;
5868eb24
BP
870 uint16_t priority;
871 char *match;
872 char *actions;
bd39395f
BP
873};
874
875static size_t
5868eb24 876ovn_lflow_hash(const struct ovn_lflow *lflow)
bd39395f 877{
5868eb24 878 size_t hash = uuid_hash(&lflow->od->key);
880fcd14 879 hash = hash_2words((lflow->stage << 16) | lflow->priority, hash);
5868eb24
BP
880 hash = hash_string(lflow->match, hash);
881 return hash_string(lflow->actions, hash);
bd39395f
BP
882}
883
5868eb24
BP
884static bool
885ovn_lflow_equal(const struct ovn_lflow *a, const struct ovn_lflow *b)
886{
887 return (a->od == b->od
880fcd14 888 && a->stage == b->stage
5868eb24
BP
889 && a->priority == b->priority
890 && !strcmp(a->match, b->match)
891 && !strcmp(a->actions, b->actions));
892}
893
894static void
895ovn_lflow_init(struct ovn_lflow *lflow, struct ovn_datapath *od,
880fcd14 896 enum ovn_stage stage, uint16_t priority,
5868eb24 897 char *match, char *actions)
bd39395f 898{
5868eb24 899 lflow->od = od;
880fcd14 900 lflow->stage = stage;
5868eb24
BP
901 lflow->priority = priority;
902 lflow->match = match;
903 lflow->actions = actions;
bd39395f
BP
904}
905
48605550 906/* Adds a row with the specified contents to the Logical_Flow table. */
bd39395f 907static void
5868eb24 908ovn_lflow_add(struct hmap *lflow_map, struct ovn_datapath *od,
880fcd14 909 enum ovn_stage stage, uint16_t priority,
5868eb24
BP
910 const char *match, const char *actions)
911{
912 struct ovn_lflow *lflow = xmalloc(sizeof *lflow);
880fcd14 913 ovn_lflow_init(lflow, od, stage, priority,
5868eb24
BP
914 xstrdup(match), xstrdup(actions));
915 hmap_insert(lflow_map, &lflow->hmap_node, ovn_lflow_hash(lflow));
916}
917
918static struct ovn_lflow *
919ovn_lflow_find(struct hmap *lflows, struct ovn_datapath *od,
880fcd14 920 enum ovn_stage stage, uint16_t priority,
5868eb24
BP
921 const char *match, const char *actions)
922{
923 struct ovn_lflow target;
880fcd14 924 ovn_lflow_init(&target, od, stage, priority,
5868eb24
BP
925 CONST_CAST(char *, match), CONST_CAST(char *, actions));
926
927 struct ovn_lflow *lflow;
928 HMAP_FOR_EACH_WITH_HASH (lflow, hmap_node, ovn_lflow_hash(&target),
929 lflows) {
930 if (ovn_lflow_equal(lflow, &target)) {
931 return lflow;
bd39395f
BP
932 }
933 }
5868eb24
BP
934 return NULL;
935}
bd39395f 936
5868eb24
BP
937static void
938ovn_lflow_destroy(struct hmap *lflows, struct ovn_lflow *lflow)
939{
940 if (lflow) {
941 hmap_remove(lflows, &lflow->hmap_node);
942 free(lflow->match);
943 free(lflow->actions);
944 free(lflow);
945 }
bd39395f
BP
946}
947
7dc88496
NS
948struct ipv4_netaddr {
949 ovs_be32 addr;
950 unsigned int plen;
951};
952
953struct ipv6_netaddr {
954 struct in6_addr addr;
955 unsigned int plen;
956};
957
958struct lport_addresses {
959 struct eth_addr ea;
960 size_t n_ipv4_addrs;
961 struct ipv4_netaddr *ipv4_addrs;
962 size_t n_ipv6_addrs;
963 struct ipv6_netaddr *ipv6_addrs;
964};
965
966/*
967 * Extracts the mac, ipv4 and ipv6 addresses from the input param 'address'
968 * which should be of the format 'MAC [IP1 IP2 ..]" where IPn should be
969 * a valid IPv4 or IPv6 address and stores them in the 'ipv4_addrs' and
970 * 'ipv6_addrs' fields of input param 'laddrs'.
971 * The caller has to free the 'ipv4_addrs' and 'ipv6_addrs' fields.
972 * If input param 'store_ipv6' is true only then extracted ipv6 addresses
973 * are stored in 'ipv6_addrs' fields.
974 * Return true if at least 'MAC' is found in 'address', false otherwise.
975 * Eg 1.
976 * If 'address' = '00:00:00:00:00:01 10.0.0.4 fe80::ea2a:eaff:fe28:3390/64
977 * 30.0.0.3/23' and 'store_ipv6' = true
978 * then returns true with laddrs->n_ipv4_addrs = 2, naddrs->n_ipv6_addrs = 1.
979 *
980 * Eg. 2
981 * If 'address' = '00:00:00:00:00:01 10.0.0.4 fe80::ea2a:eaff:fe28:3390/64
982 * 30.0.0.3/23' and 'store_ipv6' = false
983 * then returns true with laddrs->n_ipv4_addrs = 2, naddrs->n_ipv6_addrs = 0.
984 *
985 * Eg 3. If 'address' = '00:00:00:00:00:01 10.0.0.4 addr 30.0.0.4', then
986 * returns true with laddrs->n_ipv4_addrs = 1 and laddrs->n_ipv6_addrs = 0.
987 */
988static bool
989extract_lport_addresses(char *address, struct lport_addresses *laddrs,
990 bool store_ipv6)
991{
992 char *buf = address;
993 int buf_index = 0;
994 char *buf_end = buf + strlen(address);
995 if (!ovs_scan_len(buf, &buf_index, ETH_ADDR_SCAN_FMT,
996 ETH_ADDR_SCAN_ARGS(laddrs->ea))) {
7dc88496
NS
997 return false;
998 }
999
1000 ovs_be32 ip4;
1001 struct in6_addr ip6;
1002 unsigned int plen;
1003 char *error;
1004
1005 laddrs->n_ipv4_addrs = 0;
1006 laddrs->n_ipv6_addrs = 0;
1007 laddrs->ipv4_addrs = NULL;
1008 laddrs->ipv6_addrs = NULL;
1009
1010 /* Loop through the buffer and extract the IPv4/IPv6 addresses
1011 * and store in the 'laddrs'. Break the loop if invalid data is found.
1012 */
1013 buf += buf_index;
1014 while (buf < buf_end) {
1015 buf_index = 0;
1016 error = ip_parse_cidr_len(buf, &buf_index, &ip4, &plen);
1017 if (!error) {
1018 laddrs->n_ipv4_addrs++;
1019 laddrs->ipv4_addrs = xrealloc(
1020 laddrs->ipv4_addrs,
1021 sizeof (struct ipv4_netaddr) * laddrs->n_ipv4_addrs);
1022 laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1].addr = ip4;
1023 laddrs->ipv4_addrs[laddrs->n_ipv4_addrs - 1].plen = plen;
1024 buf += buf_index;
1025 continue;
1026 }
1027 free(error);
1028 error = ipv6_parse_cidr_len(buf, &buf_index, &ip6, &plen);
1029 if (!error && store_ipv6) {
1030 laddrs->n_ipv6_addrs++;
1031 laddrs->ipv6_addrs = xrealloc(
1032 laddrs->ipv6_addrs,
1033 sizeof(struct ipv6_netaddr) * laddrs->n_ipv6_addrs);
1034 memcpy(&laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1].addr, &ip6,
1035 sizeof(struct in6_addr));
1036 laddrs->ipv6_addrs[laddrs->n_ipv6_addrs - 1].plen = plen;
1037 }
1038
1039 if (error) {
1040 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
1041 VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", address);
1042 free(error);
1043 break;
1044 }
1045 buf += buf_index;
1046 }
1047
1048 return true;
1049}
1050
bd39395f
BP
1051/* Appends port security constraints on L2 address field 'eth_addr_field'
1052 * (e.g. "eth.src" or "eth.dst") to 'match'. 'port_security', with
1053 * 'n_port_security' elements, is the collection of port_security constraints
f7cb14cd 1054 * from an OVN_NB Logical_Port row. */
bd39395f 1055static void
685f4dfe
NS
1056build_port_security_l2(const char *eth_addr_field,
1057 char **port_security, size_t n_port_security,
1058 struct ds *match)
bd39395f
BP
1059{
1060 size_t base_len = match->length;
1061 ds_put_format(match, " && %s == {", eth_addr_field);
1062
1063 size_t n = 0;
1064 for (size_t i = 0; i < n_port_security; i++) {
74ff3298 1065 struct eth_addr ea;
f7cb14cd 1066
74ff3298 1067 if (eth_addr_from_string(port_security[i], &ea)) {
f7cb14cd 1068 ds_put_format(match, ETH_ADDR_FMT, ETH_ADDR_ARGS(ea));
bd39395f
BP
1069 ds_put_char(match, ' ');
1070 n++;
1071 }
1072 }
f7cb14cd 1073 ds_chomp(match, ' ');
bd39395f 1074 ds_put_cstr(match, "}");
4edcdcf4 1075
bd39395f
BP
1076 if (!n) {
1077 match->length = base_len;
1078 }
1079}
1080
685f4dfe
NS
1081static void
1082build_port_security_ipv6_nd_flow(
1083 struct ds *match, struct eth_addr ea, struct ipv6_netaddr *ipv6_addrs,
1084 int n_ipv6_addrs)
1085{
1086 ds_put_format(match, " && ip6 && nd && ((nd.sll == "ETH_ADDR_FMT" || "
1087 "nd.sll == "ETH_ADDR_FMT") || ((nd.tll == "ETH_ADDR_FMT" || "
1088 "nd.tll == "ETH_ADDR_FMT")", ETH_ADDR_ARGS(eth_addr_zero),
1089 ETH_ADDR_ARGS(ea), ETH_ADDR_ARGS(eth_addr_zero),
1090 ETH_ADDR_ARGS(ea));
1091 if (!n_ipv6_addrs) {
1092 ds_put_cstr(match, "))");
1093 return;
1094 }
1095
1096 char ip6_str[INET6_ADDRSTRLEN + 1];
1097 struct in6_addr lla;
1098 in6_generate_lla(ea, &lla);
1099 memset(ip6_str, 0, sizeof(ip6_str));
1100 ipv6_string_mapped(ip6_str, &lla);
1101 ds_put_format(match, " && (nd.target == %s", ip6_str);
1102
1103 for(int i = 0; i < n_ipv6_addrs; i++) {
1104 memset(ip6_str, 0, sizeof(ip6_str));
1105 ipv6_string_mapped(ip6_str, &ipv6_addrs[i].addr);
1106 ds_put_format(match, " || nd.target == %s", ip6_str);
1107 }
1108
1109 ds_put_format(match, ")))");
1110}
1111
1112static void
1113build_port_security_ipv6_flow(
1114 enum ovn_pipeline pipeline, struct ds *match, struct eth_addr ea,
1115 struct ipv6_netaddr *ipv6_addrs, int n_ipv6_addrs)
1116{
1117 char ip6_str[INET6_ADDRSTRLEN + 1];
1118
1119 ds_put_format(match, " && %s == {",
1120 pipeline == P_IN ? "ip6.src" : "ip6.dst");
1121
1122 /* Allow link-local address. */
1123 struct in6_addr lla;
1124 in6_generate_lla(ea, &lla);
1125 ipv6_string_mapped(ip6_str, &lla);
1126 ds_put_format(match, "%s, ", ip6_str);
1127
1128 /* Allow ip6.src=:: and ip6.dst=ff00::/8 for ND packets */
1129 ds_put_cstr(match, pipeline == P_IN ? "::" : "ff00::/8");
1130 for(int i = 0; i < n_ipv6_addrs; i++) {
1131 ipv6_string_mapped(ip6_str, &ipv6_addrs[i].addr);
1132 ds_put_format(match, ", %s", ip6_str);
1133 }
1134 ds_put_cstr(match, "}");
1135}
1136
1137/**
1138 * Build port security constraints on ARP and IPv6 ND fields
1139 * and add logical flows to S_SWITCH_IN_PORT_SEC_ND stage.
1140 *
1141 * For each port security of the logical port, following
1142 * logical flows are added
1143 * - If the port security has no IP (both IPv4 and IPv6) or
1144 * if it has IPv4 address(es)
1145 * - Priority 90 flow to allow ARP packets for known MAC addresses
1146 * in the eth.src and arp.spa fields. If the port security
1147 * has IPv4 addresses, allow known IPv4 addresses in the arp.tpa field.
1148 *
1149 * - If the port security has no IP (both IPv4 and IPv6) or
1150 * if it has IPv6 address(es)
1151 * - Priority 90 flow to allow IPv6 ND packets for known MAC addresses
1152 * in the eth.src and nd.sll/nd.tll fields. If the port security
1153 * has IPv6 addresses, allow known IPv6 addresses in the nd.target field
1154 * for IPv6 Neighbor Advertisement packet.
1155 *
1156 * - Priority 80 flow to drop ARP and IPv6 ND packets.
1157 */
1158static void
1159build_port_security_nd(struct ovn_port *op, struct hmap *lflows)
1160{
1161 for (size_t i = 0; i < op->nbs->n_port_security; i++) {
1162 struct lport_addresses ps;
1163 if (!extract_lport_addresses(op->nbs->port_security[i], &ps, true)) {
1164 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
1165 VLOG_INFO_RL(&rl, "invalid syntax '%s' in port security. No MAC"
1166 " address found", op->nbs->port_security[i]);
1167 continue;
1168 }
1169
1170 bool no_ip = !(ps.n_ipv4_addrs || ps.n_ipv6_addrs);
1171 struct ds match = DS_EMPTY_INITIALIZER;
1172
1173 if (ps.n_ipv4_addrs || no_ip) {
1174 ds_put_format(
1175 &match, "inport == %s && eth.src == "ETH_ADDR_FMT" && arp.sha == "
1176 ETH_ADDR_FMT, op->json_key, ETH_ADDR_ARGS(ps.ea),
1177 ETH_ADDR_ARGS(ps.ea));
1178
1179 if (ps.n_ipv4_addrs) {
1180 ds_put_cstr(&match, " && (");
1181 for (size_t i = 0; i < ps.n_ipv4_addrs; i++) {
1182 ds_put_format(&match, "arp.spa == "IP_FMT" || ",
1183 IP_ARGS(ps.ipv4_addrs[i].addr));
1184 }
1185 ds_chomp(&match, ' ');
1186 ds_chomp(&match, '|');
1187 ds_chomp(&match, '|');
1188 ds_put_cstr(&match, ")");
1189 }
1190 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90,
1191 ds_cstr(&match), "next;");
1192 ds_destroy(&match);
1193 }
1194
1195 if (ps.n_ipv6_addrs || no_ip) {
1196 ds_init(&match);
1197 ds_put_format(&match, "inport == %s && eth.src == "ETH_ADDR_FMT,
1198 op->json_key, ETH_ADDR_ARGS(ps.ea));
1199 build_port_security_ipv6_nd_flow(&match, ps.ea, ps.ipv6_addrs,
1200 ps.n_ipv6_addrs);
1201 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 90,
1202 ds_cstr(&match), "next;");
1203 ds_destroy(&match);
1204 }
1205 free(ps.ipv4_addrs);
1206 free(ps.ipv6_addrs);
1207 }
1208
1209 char *match = xasprintf("inport == %s && (arp || nd)", op->json_key);
1210 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_ND, 80,
1211 match, "drop;");
1212 free(match);
1213}
1214
1215/**
1216 * Build port security constraints on IPv4 and IPv6 src and dst fields
1217 * and add logical flows to S_SWITCH_(IN/OUT)_PORT_SEC_IP stage.
1218 *
1219 * For each port security of the logical port, following
1220 * logical flows are added
1221 * - If the port security has IPv4 addresses,
1222 * - Priority 90 flow to allow IPv4 packets for known IPv4 addresses
1223 *
1224 * - If the port security has IPv6 addresses,
1225 * - Priority 90 flow to allow IPv6 packets for known IPv6 addresses
1226 *
1227 * - If the port security has IPv4 addresses or IPv6 addresses or both
1228 * - Priority 80 flow to drop all IPv4 and IPv6 traffic
1229 */
1230static void
1231build_port_security_ip(enum ovn_pipeline pipeline, struct ovn_port *op,
1232 struct hmap *lflows)
1233{
1234 char *port_direction;
1235 enum ovn_stage stage;
1236 if (pipeline == P_IN) {
1237 port_direction = "inport";
1238 stage = S_SWITCH_IN_PORT_SEC_IP;
1239 } else {
1240 port_direction = "outport";
1241 stage = S_SWITCH_OUT_PORT_SEC_IP;
1242 }
1243
1244 for (size_t i = 0; i < op->nbs->n_port_security; i++) {
1245 struct lport_addresses ps;
1246 if (!extract_lport_addresses(op->nbs->port_security[i], &ps, true)) {
1247 continue;
1248 }
1249
1250 if (!(ps.n_ipv4_addrs || ps.n_ipv6_addrs)) {
1251 continue;
1252 }
1253
1254 if (ps.n_ipv4_addrs) {
1255 struct ds match = DS_EMPTY_INITIALIZER;
1256 if (pipeline == P_IN) {
1257 ds_put_format(&match, "inport == %s && eth.src == "ETH_ADDR_FMT
1258 " && ip4.src == {0.0.0.0, ", op->json_key,
1259 ETH_ADDR_ARGS(ps.ea));
1260 } else {
1261 ds_put_format(&match, "outport == %s && eth.dst == "ETH_ADDR_FMT
1262 " && ip4.dst == {255.255.255.255, 224.0.0.0/4, ",
1263 op->json_key, ETH_ADDR_ARGS(ps.ea));
1264 }
1265
1266 for (int i = 0; i < ps.n_ipv4_addrs; i++) {
1267 ds_put_format(&match, IP_FMT", ", IP_ARGS(ps.ipv4_addrs[i].addr));
1268 }
1269
1270 /* Replace ", " by "}". */
1271 ds_chomp(&match, ' ');
1272 ds_chomp(&match, ',');
1273 ds_put_cstr(&match, "}");
1274 ovn_lflow_add(lflows, op->od, stage, 90, ds_cstr(&match), "next;");
1275 ds_destroy(&match);
1276 free(ps.ipv4_addrs);
1277 }
1278
1279 if (ps.n_ipv6_addrs) {
1280 struct ds match = DS_EMPTY_INITIALIZER;
1281 ds_put_format(&match, "%s == %s && %s == "ETH_ADDR_FMT"",
1282 port_direction, op->json_key,
1283 pipeline == P_IN ? "eth.src" : "eth.dst",
1284 ETH_ADDR_ARGS(ps.ea));
1285 build_port_security_ipv6_flow(pipeline, &match, ps.ea,
1286 ps.ipv6_addrs, ps.n_ipv6_addrs);
1287 ovn_lflow_add(lflows, op->od, stage, 90,
1288 ds_cstr(&match), "next;");
1289 ds_destroy(&match);
1290 free(ps.ipv6_addrs);
1291 }
1292
1293 char *match = xasprintf(
1294 "%s == %s && %s == "ETH_ADDR_FMT" && ip", port_direction,
1295 op->json_key, pipeline == P_IN ? "eth.src" : "eth.dst",
1296 ETH_ADDR_ARGS(ps.ea));
1297 ovn_lflow_add(lflows, op->od, stage, 80, match, "drop;");
1298 free(match);
1299 }
1300}
1301
95a9a275
RB
1302static bool
1303lport_is_enabled(const struct nbrec_logical_port *lport)
1304{
1305 return !lport->enabled || *lport->enabled;
1306}
1307
4c7bf534
NS
1308static bool
1309lport_is_up(const struct nbrec_logical_port *lport)
1310{
1311 return !lport->up || *lport->up;
1312}
1313
78aab811
JP
1314static bool
1315has_stateful_acl(struct ovn_datapath *od)
1316{
9975d7be
BP
1317 for (size_t i = 0; i < od->nbs->n_acls; i++) {
1318 struct nbrec_acl *acl = od->nbs->acls[i];
78aab811
JP
1319 if (!strcmp(acl->action, "allow-related")) {
1320 return true;
1321 }
1322 }
1323
1324 return false;
1325}
1326
1327static void
48fcdb47 1328build_acls(struct ovn_datapath *od, struct hmap *lflows, struct hmap *ports)
78aab811
JP
1329{
1330 bool has_stateful = has_stateful_acl(od);
48fcdb47 1331 struct ovn_port *op;
78aab811
JP
1332
1333 /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are
1334 * allowed by default. */
880fcd14
BP
1335 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 0, "1", "next;");
1336 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 0, "1", "next;");
78aab811
JP
1337
1338 /* Ingress and Egress ACL Table (Priority 0): Packets are allowed by
1339 * default. A related rule at priority 1 is added below if there
1340 * are any stateful ACLs in this datapath. */
880fcd14
BP
1341 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 0, "1", "next;");
1342 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 0, "1", "next;");
78aab811
JP
1343
1344 /* If there are any stateful ACL rules in this dapapath, we must
1345 * send all IP packets through the conntrack action, which handles
1346 * defragmentation, in order to match L4 headers. */
1347 if (has_stateful) {
48fcdb47
WL
1348 HMAP_FOR_EACH (op, key_node, ports) {
1349 if (op->od == od && !strcmp(op->nbs->type, "router")) {
501f95e1
JP
1350 /* Can't use ct() for router ports. Consider the
1351 * following configuration: lp1(10.0.0.2) on
1352 * hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, For a
1353 * ping from lp1 to lp2, First, the response will go
1354 * through ct() with a zone for lp2 in the ls2 ingress
1355 * pipeline on hostB. That ct zone knows about this
1356 * connection. Next, it goes through ct() with the zone
1357 * for the router port in the egress pipeline of ls2 on
1358 * hostB. This zone does not know about the connection,
1359 * as the icmp request went through the logical router
1360 * on hostA, not hostB. This would only work with
1361 * distributed conntrack state across all chassis. */
1362 struct ds match_in = DS_EMPTY_INITIALIZER;
1363 struct ds match_out = DS_EMPTY_INITIALIZER;
1364
48fcdb47
WL
1365 ds_put_format(&match_in, "ip && inport == %s", op->json_key);
1366 ds_put_format(&match_out, "ip && outport == %s", op->json_key);
501f95e1
JP
1367 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 110,
1368 ds_cstr(&match_in), "next;");
1369 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 110,
1370 ds_cstr(&match_out), "next;");
48fcdb47
WL
1371
1372 ds_destroy(&match_in);
1373 ds_destroy(&match_out);
1374 }
1375 }
1376
78aab811
JP
1377 /* Ingress and Egress Pre-ACL Table (Priority 100).
1378 *
1379 * Regardless of whether the ACL is "from-lport" or "to-lport",
1380 * we need rules in both the ingress and egress table, because
1381 * the return traffic needs to be followed. */
880fcd14
BP
1382 ovn_lflow_add(lflows, od, S_SWITCH_IN_PRE_ACL, 100, "ip", "ct_next;");
1383 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PRE_ACL, 100, "ip", "ct_next;");
78aab811
JP
1384
1385 /* Ingress and Egress ACL Table (Priority 1).
1386 *
1387 * By default, traffic is allowed. This is partially handled by
1388 * the Priority 0 ACL flows added earlier, but we also need to
1389 * commit IP flows. This is because, while the initiater's
1390 * direction may not have any stateful rules, the server's may
1391 * and then its return traffic would not have an associated
1392 * conntrack entry and would return "+invalid". */
880fcd14 1393 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, 1, "ip",
78aab811 1394 "ct_commit; next;");
880fcd14 1395 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, 1, "ip",
78aab811
JP
1396 "ct_commit; next;");
1397
1398 /* Ingress and Egress ACL Table (Priority 65535).
1399 *
1400 * Always drop traffic that's in an invalid state. This is
1401 * enforced at a higher priority than ACLs can be defined. */
880fcd14 1402 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
78aab811 1403 "ct.inv", "drop;");
880fcd14 1404 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
78aab811
JP
1405 "ct.inv", "drop;");
1406
1407 /* Ingress and Egress ACL Table (Priority 65535).
1408 *
1409 * Always allow traffic that is established to a committed
1410 * conntrack entry. This is enforced at a higher priority than
1411 * ACLs can be defined. */
880fcd14 1412 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
78aab811
JP
1413 "ct.est && !ct.rel && !ct.new && !ct.inv",
1414 "next;");
880fcd14 1415 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
78aab811
JP
1416 "ct.est && !ct.rel && !ct.new && !ct.inv",
1417 "next;");
1418
1419 /* Ingress and Egress ACL Table (Priority 65535).
1420 *
1421 * Always allow traffic that is related to an existing conntrack
1422 * entry. This is enforced at a higher priority than ACLs can
1423 * be defined.
1424 *
1425 * NOTE: This does not support related data sessions (eg,
1426 * a dynamically negotiated FTP data channel), but will allow
1427 * related traffic such as an ICMP Port Unreachable through
1428 * that's generated from a non-listening UDP port. */
880fcd14 1429 ovn_lflow_add(lflows, od, S_SWITCH_IN_ACL, UINT16_MAX,
78aab811
JP
1430 "!ct.est && ct.rel && !ct.new && !ct.inv",
1431 "next;");
880fcd14 1432 ovn_lflow_add(lflows, od, S_SWITCH_OUT_ACL, UINT16_MAX,
78aab811
JP
1433 "!ct.est && ct.rel && !ct.new && !ct.inv",
1434 "next;");
1435 }
1436
1437 /* Ingress or Egress ACL Table (Various priorities). */
9975d7be
BP
1438 for (size_t i = 0; i < od->nbs->n_acls; i++) {
1439 struct nbrec_acl *acl = od->nbs->acls[i];
78aab811 1440 bool ingress = !strcmp(acl->direction, "from-lport") ? true :false;
880fcd14 1441 enum ovn_stage stage = ingress ? S_SWITCH_IN_ACL : S_SWITCH_OUT_ACL;
78aab811
JP
1442
1443 if (!strcmp(acl->action, "allow")) {
1444 /* If there are any stateful flows, we must even commit "allow"
1445 * actions. This is because, while the initiater's
1446 * direction may not have any stateful rules, the server's
1447 * may and then its return traffic would not have an
1448 * associated conntrack entry and would return "+invalid". */
1449 const char *actions = has_stateful ? "ct_commit; next;" : "next;";
6bb4a18e
JP
1450 ovn_lflow_add(lflows, od, stage,
1451 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1452 acl->match, actions);
1453 } else if (!strcmp(acl->action, "allow-related")) {
1454 struct ds match = DS_EMPTY_INITIALIZER;
1455
1456 /* Commit the connection tracking entry, which allows all
1457 * other traffic related to this entry to flow due to the
1458 * 65535 priority flow defined earlier. */
1459 ds_put_format(&match, "ct.new && (%s)", acl->match);
6bb4a18e
JP
1460 ovn_lflow_add(lflows, od, stage,
1461 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1462 ds_cstr(&match), "ct_commit; next;");
1463
1464 ds_destroy(&match);
1465 } else if (!strcmp(acl->action, "drop")) {
6bb4a18e
JP
1466 ovn_lflow_add(lflows, od, stage,
1467 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1468 acl->match, "drop;");
1469 } else if (!strcmp(acl->action, "reject")) {
1470 /* xxx Need to support "reject". */
1471 VLOG_INFO("reject is not a supported action");
6bb4a18e
JP
1472 ovn_lflow_add(lflows, od, stage,
1473 acl->priority + OVN_ACL_PRI_OFFSET,
78aab811
JP
1474 acl->match, "drop;");
1475 }
1476 }
1477}
1478
bd39395f 1479static void
9975d7be
BP
1480build_lswitch_flows(struct hmap *datapaths, struct hmap *ports,
1481 struct hmap *lflows, struct hmap *mcgroups)
bd39395f 1482{
5cff6b99
BP
1483 /* This flow table structure is documented in ovn-northd(8), so please
1484 * update ovn-northd.8.xml if you change anything. */
1485
9975d7be 1486 /* Build pre-ACL and ACL tables for both ingress and egress.
685f4dfe 1487 * Ingress tables 3 and 4. Egress tables 0 and 1. */
5868eb24
BP
1488 struct ovn_datapath *od;
1489 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1490 if (!od->nbs) {
1491 continue;
1492 }
1493
48fcdb47 1494 build_acls(od, lflows, ports);
9975d7be
BP
1495 }
1496
1497 /* Logical switch ingress table 0: Admission control framework (priority
1498 * 100). */
1499 HMAP_FOR_EACH (od, key_node, datapaths) {
1500 if (!od->nbs) {
1501 continue;
1502 }
1503
bd39395f 1504 /* Logical VLANs not supported. */
685f4dfe 1505 ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_L2, 100, "vlan.present",
091e3af9 1506 "drop;");
bd39395f
BP
1507
1508 /* Broadcast/multicast source address is invalid. */
685f4dfe 1509 ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_L2, 100, "eth.src[40]",
091e3af9 1510 "drop;");
bd39395f 1511
35060cdc
BP
1512 /* Port security flows have priority 50 (see below) and will continue
1513 * to the next table if packet source is acceptable. */
bd39395f
BP
1514 }
1515
685f4dfe
NS
1516 /* Logical switch ingress table 0: Ingress port security - L2
1517 * (priority 50).
1518 * Ingress table 1: Ingress port security - IP (priority 90 and 80)
1519 * Ingress table 2: Ingress port security - ND (priority 90 and 80)
1520 */
5868eb24
BP
1521 struct ovn_port *op;
1522 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1523 if (!op->nbs) {
1524 continue;
1525 }
1526
1527 if (!lport_is_enabled(op->nbs)) {
96af668a
BP
1528 /* Drop packets from disabled logical ports (since logical flow
1529 * tables are default-drop). */
1530 continue;
1531 }
1532
5868eb24 1533 struct ds match = DS_EMPTY_INITIALIZER;
9975d7be 1534 ds_put_format(&match, "inport == %s", op->json_key);
685f4dfe
NS
1535 build_port_security_l2(
1536 "eth.src", op->nbs->port_security, op->nbs->n_port_security,
1537 &match);
1538 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_PORT_SEC_L2, 50,
96af668a 1539 ds_cstr(&match), "next;");
5868eb24 1540 ds_destroy(&match);
685f4dfe
NS
1541
1542 if (op->nbs->n_port_security) {
1543 build_port_security_ip(P_IN, op, lflows);
1544 build_port_security_nd(op, lflows);
1545 }
1546 }
1547
1548 /* Ingress table 1 and 2: Port security - IP and ND, by default goto next.
1549 * (priority 0)*/
1550 HMAP_FOR_EACH (od, key_node, datapaths) {
1551 if (!od->nbs) {
1552 continue;
1553 }
1554
1555 ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_ND, 0, "1", "next;");
1556 ovn_lflow_add(lflows, od, S_SWITCH_IN_PORT_SEC_IP, 0, "1", "next;");
5868eb24 1557 }
445a266a 1558
fa128126
HZ
1559 /* Ingress table 3: ARP responder, skip requests coming from localnet ports.
1560 * (priority 100). */
1561 HMAP_FOR_EACH (op, key_node, ports) {
1562 if (!op->nbs) {
1563 continue;
1564 }
1565
1566 if (!strcmp(op->nbs->type, "localnet")) {
1567 char *match = xasprintf("inport == %s", op->json_key);
1568 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_RSP, 100,
1569 match, "next;");
1570 free(match);
1571 }
1572 }
1573
685f4dfe 1574 /* Ingress table 5: ARP responder, reply for known IPs.
fa128126 1575 * (priority 50). */
57d143eb
HZ
1576 HMAP_FOR_EACH (op, key_node, ports) {
1577 if (!op->nbs) {
1578 continue;
1579 }
1580
4c7bf534
NS
1581 /*
1582 * Add ARP reply flows if either the
1583 * - port is up or
1584 * - port type is router
1585 */
1586 if (!lport_is_up(op->nbs) && strcmp(op->nbs->type, "router")) {
1587 continue;
1588 }
1589
57d143eb 1590 for (size_t i = 0; i < op->nbs->n_addresses; i++) {
7dc88496
NS
1591 struct lport_addresses laddrs;
1592 if (!extract_lport_addresses(op->nbs->addresses[i], &laddrs,
1593 false)) {
1594 continue;
1595 }
1596 for (size_t j = 0; j < laddrs.n_ipv4_addrs; j++) {
57d143eb 1597 char *match = xasprintf(
7dc88496
NS
1598 "arp.tpa == "IP_FMT" && arp.op == 1",
1599 IP_ARGS(laddrs.ipv4_addrs[j].addr));
57d143eb
HZ
1600 char *actions = xasprintf(
1601 "eth.dst = eth.src; "
1602 "eth.src = "ETH_ADDR_FMT"; "
1603 "arp.op = 2; /* ARP reply */ "
1604 "arp.tha = arp.sha; "
1605 "arp.sha = "ETH_ADDR_FMT"; "
1606 "arp.tpa = arp.spa; "
1607 "arp.spa = "IP_FMT"; "
1608 "outport = inport; "
1609 "inport = \"\"; /* Allow sending out inport. */ "
1610 "output;",
7dc88496
NS
1611 ETH_ADDR_ARGS(laddrs.ea),
1612 ETH_ADDR_ARGS(laddrs.ea),
1613 IP_ARGS(laddrs.ipv4_addrs[j].addr));
fa128126 1614 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_ARP_RSP, 50,
57d143eb
HZ
1615 match, actions);
1616 free(match);
1617 free(actions);
1618 }
7dc88496
NS
1619
1620 free(laddrs.ipv4_addrs);
57d143eb
HZ
1621 }
1622 }
1623
685f4dfe 1624 /* Ingress table 5: ARP responder, by default goto next.
fa128126
HZ
1625 * (priority 0)*/
1626 HMAP_FOR_EACH (od, key_node, datapaths) {
1627 if (!od->nbs) {
1628 continue;
1629 }
1630
1631 ovn_lflow_add(lflows, od, S_SWITCH_IN_ARP_RSP, 0, "1", "next;");
1632 }
1633
685f4dfe 1634 /* Ingress table 6: Destination lookup, broadcast and multicast handling
5868eb24
BP
1635 * (priority 100). */
1636 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1637 if (!op->nbs) {
1638 continue;
1639 }
1640
1641 if (lport_is_enabled(op->nbs)) {
1642 ovn_multicast_add(mcgroups, &mc_flood, op);
445a266a 1643 }
5868eb24
BP
1644 }
1645 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1646 if (!od->nbs) {
1647 continue;
1648 }
1649
1650 ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 100, "eth.mcast",
5868eb24 1651 "outport = \""MC_FLOOD"\"; output;");
bd39395f 1652 }
bd39395f 1653
685f4dfe 1654 /* Ingress table 6: Destination lookup, unicast handling (priority 50), */
5868eb24 1655 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1656 if (!op->nbs) {
1657 continue;
1658 }
1659
1660 for (size_t i = 0; i < op->nbs->n_addresses; i++) {
74ff3298 1661 struct eth_addr mac;
5868eb24 1662
9975d7be 1663 if (eth_addr_from_string(op->nbs->addresses[i], &mac)) {
5868eb24
BP
1664 struct ds match, actions;
1665
1666 ds_init(&match);
9975d7be
BP
1667 ds_put_format(&match, "eth.dst == "ETH_ADDR_FMT,
1668 ETH_ADDR_ARGS(mac));
5868eb24
BP
1669
1670 ds_init(&actions);
9975d7be
BP
1671 ds_put_format(&actions, "outport = %s; output;", op->json_key);
1672 ovn_lflow_add(lflows, op->od, S_SWITCH_IN_L2_LKUP, 50,
5868eb24
BP
1673 ds_cstr(&match), ds_cstr(&actions));
1674 ds_destroy(&actions);
1675 ds_destroy(&match);
9975d7be
BP
1676 } else if (!strcmp(op->nbs->addresses[i], "unknown")) {
1677 if (lport_is_enabled(op->nbs)) {
1678 ovn_multicast_add(mcgroups, &mc_unknown, op);
96af668a
BP
1679 op->od->has_unknown = true;
1680 }
5868eb24
BP
1681 } else {
1682 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
445a266a 1683
2fa326a3
BP
1684 VLOG_INFO_RL(&rl,
1685 "%s: invalid syntax '%s' in addresses column",
9975d7be 1686 op->nbs->name, op->nbs->addresses[i]);
445a266a
BP
1687 }
1688 }
bd39395f
BP
1689 }
1690
685f4dfe 1691 /* Ingress table 6: Destination lookup for unknown MACs (priority 0). */
5868eb24 1692 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1693 if (!od->nbs) {
1694 continue;
1695 }
1696
5868eb24 1697 if (od->has_unknown) {
9975d7be 1698 ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 0, "1",
5868eb24 1699 "outport = \""MC_UNKNOWN"\"; output;");
445a266a 1700 }
bd39395f
BP
1701 }
1702
685f4dfe
NS
1703 /* Egress table 2: Egress port security - IP (priority 0)
1704 * port security L2 - multicast/broadcast (priority
5868eb24
BP
1705 * 100). */
1706 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1707 if (!od->nbs) {
1708 continue;
1709 }
1710
685f4dfe
NS
1711 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PORT_SEC_IP, 0, "1", "next;");
1712 ovn_lflow_add(lflows, od, S_SWITCH_OUT_PORT_SEC_L2, 100, "eth.mcast",
091e3af9 1713 "output;");
48f42f3a
RB
1714 }
1715
685f4dfe
NS
1716 /* Egress table 2: Egress port security - IP (priorities 90 and 80)
1717 * if port security enabled.
1718 *
1719 * Egress table 3: Egress port security - L2 (priorities 50 and 150).
d770a830
BP
1720 *
1721 * Priority 50 rules implement port security for enabled logical port.
1722 *
1723 * Priority 150 rules drop packets to disabled logical ports, so that they
1724 * don't even receive multicast or broadcast packets. */
5868eb24 1725 HMAP_FOR_EACH (op, key_node, ports) {
9975d7be
BP
1726 if (!op->nbs) {
1727 continue;
1728 }
1729
1730 struct ds match = DS_EMPTY_INITIALIZER;
1731 ds_put_format(&match, "outport == %s", op->json_key);
1732 if (lport_is_enabled(op->nbs)) {
685f4dfe
NS
1733 build_port_security_l2("eth.dst", op->nbs->port_security,
1734 op->nbs->n_port_security, &match);
1735 ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 50,
d770a830
BP
1736 ds_cstr(&match), "output;");
1737 } else {
685f4dfe 1738 ovn_lflow_add(lflows, op->od, S_SWITCH_OUT_PORT_SEC_L2, 150,
d770a830
BP
1739 ds_cstr(&match), "drop;");
1740 }
eb00399e 1741
5868eb24 1742 ds_destroy(&match);
685f4dfe
NS
1743
1744 if (op->nbs->n_port_security) {
1745 build_port_security_ip(P_OUT, op, lflows);
1746 }
eb00399e 1747 }
9975d7be 1748}
eb00399e 1749
9975d7be
BP
1750static bool
1751lrport_is_enabled(const struct nbrec_logical_router_port *lrport)
1752{
1753 return !lrport->enabled || *lrport->enabled;
1754}
1755
1756static void
0bac7164 1757add_route(struct hmap *lflows, const struct ovn_port *op,
9975d7be
BP
1758 ovs_be32 network, ovs_be32 mask, ovs_be32 gateway)
1759{
1760 char *match = xasprintf("ip4.dst == "IP_FMT"/"IP_FMT,
1761 IP_ARGS(network), IP_ARGS(mask));
1762
1763 struct ds actions = DS_EMPTY_INITIALIZER;
47f3b59b 1764 ds_put_cstr(&actions, "ip.ttl--; reg0 = ");
9975d7be
BP
1765 if (gateway) {
1766 ds_put_format(&actions, IP_FMT, IP_ARGS(gateway));
1767 } else {
1768 ds_put_cstr(&actions, "ip4.dst");
1769 }
0bac7164
BP
1770 ds_put_format(&actions,
1771 "; "
1772 "reg1 = "IP_FMT"; "
1773 "eth.src = "ETH_ADDR_FMT"; "
1774 "outport = %s; "
1775 "next;",
1776 IP_ARGS(op->ip), ETH_ADDR_ARGS(op->mac), op->json_key);
9975d7be
BP
1777
1778 /* The priority here is calculated to implement longest-prefix-match
1779 * routing. */
0bac7164 1780 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING,
9975d7be
BP
1781 count_1bits(ntohl(mask)), match, ds_cstr(&actions));
1782 ds_destroy(&actions);
1783 free(match);
1784}
1785
1786static void
1787build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
1788 struct hmap *lflows)
1789{
1790 /* This flow table structure is documented in ovn-northd(8), so please
1791 * update ovn-northd.8.xml if you change anything. */
1792
9975d7be
BP
1793 /* Logical router ingress table 0: Admission control framework. */
1794 struct ovn_datapath *od;
1795 HMAP_FOR_EACH (od, key_node, datapaths) {
1796 if (!od->nbr) {
1797 continue;
1798 }
1799
1800 /* Logical VLANs not supported.
1801 * Broadcast/multicast source address is invalid. */
1802 ovn_lflow_add(lflows, od, S_ROUTER_IN_ADMISSION, 100,
1803 "vlan.present || eth.src[40]", "drop;");
1804 }
1805
1806 /* Logical router ingress table 0: match (priority 50). */
1807 struct ovn_port *op;
1808 HMAP_FOR_EACH (op, key_node, ports) {
1809 if (!op->nbr) {
1810 continue;
1811 }
1812
1813 if (!lrport_is_enabled(op->nbr)) {
1814 /* Drop packets from disabled logical ports (since logical flow
1815 * tables are default-drop). */
1816 continue;
1817 }
1818
1819 char *match = xasprintf(
1820 "(eth.mcast || eth.dst == "ETH_ADDR_FMT") && inport == %s",
1821 ETH_ADDR_ARGS(op->mac), op->json_key);
1822 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_ADMISSION, 50,
1823 match, "next;");
e2229be9 1824 free(match);
9975d7be
BP
1825 }
1826
1827 /* Logical router ingress table 1: IP Input. */
78aab811 1828 HMAP_FOR_EACH (od, key_node, datapaths) {
9975d7be
BP
1829 if (!od->nbr) {
1830 continue;
1831 }
1832
1833 /* L3 admission control: drop multicast and broadcast source, localhost
1834 * source or destination, and zero network source or destination
1835 * (priority 100). */
1836 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 100,
1837 "ip4.mcast || "
1838 "ip4.src == 255.255.255.255 || "
1839 "ip4.src == 127.0.0.0/8 || "
1840 "ip4.dst == 127.0.0.0/8 || "
1841 "ip4.src == 0.0.0.0/8 || "
1842 "ip4.dst == 0.0.0.0/8",
1843 "drop;");
1844
0bac7164
BP
1845 /* ARP reply handling. Use ARP replies to populate the logical
1846 * router's ARP table. */
1847 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 90, "arp.op == 2",
1848 "put_arp(inport, arp.spa, arp.sha);");
1849
9975d7be
BP
1850 /* Drop Ethernet local broadcast. By definition this traffic should
1851 * not be forwarded.*/
1852 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
1853 "eth.bcast", "drop;");
1854
1855 /* Drop IP multicast. */
1856 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 50,
1857 "ip4.mcast", "drop;");
1858
1859 /* TTL discard.
1860 *
1861 * XXX Need to send ICMP time exceeded if !ip.later_frag. */
1862 char *match = xasprintf("ip4 && ip.ttl == {0, 1}");
1863 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 30, match, "drop;");
1864 free(match);
1865
1866 /* Pass other traffic not already handled to the next table for
1867 * routing. */
1868 ovn_lflow_add(lflows, od, S_ROUTER_IN_IP_INPUT, 0, "1", "next;");
78aab811
JP
1869 }
1870
9975d7be
BP
1871 HMAP_FOR_EACH (op, key_node, ports) {
1872 if (!op->nbr) {
1873 continue;
1874 }
1875
1876 /* L3 admission control: drop packets that originate from an IP address
1877 * owned by the router or a broadcast address known to the router
1878 * (priority 100). */
1879 char *match = xasprintf("ip4.src == {"IP_FMT", "IP_FMT"}",
1880 IP_ARGS(op->ip), IP_ARGS(op->bcast));
1881 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
1882 match, "drop;");
1883 free(match);
1884
dd7652e6
JP
1885 /* ICMP echo reply. These flows reply to ICMP echo requests
1886 * received for the router's IP address. */
1887 match = xasprintf(
1888 "inport == %s && (ip4.dst == "IP_FMT" || ip4.dst == "IP_FMT") && "
1889 "icmp4.type == 8 && icmp4.code == 0",
1890 op->json_key, IP_ARGS(op->ip), IP_ARGS(op->bcast));
1891 char *actions = xasprintf(
1892 "ip4.dst = ip4.src; "
1893 "ip4.src = "IP_FMT"; "
1894 "ip.ttl = 255; "
1895 "icmp4.type = 0; "
1896 "inport = \"\"; /* Allow sending out inport. */ "
1897 "next; ",
1898 IP_ARGS(op->ip));
1899 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
1900 match, actions);
1901 free(match);
1902 free(actions);
1903
9975d7be
BP
1904 /* ARP reply. These flows reply to ARP requests for the router's own
1905 * IP address. */
1906 match = xasprintf(
1907 "inport == %s && arp.tpa == "IP_FMT" && arp.op == 1",
1908 op->json_key, IP_ARGS(op->ip));
dd7652e6 1909 actions = xasprintf(
9975d7be
BP
1910 "eth.dst = eth.src; "
1911 "eth.src = "ETH_ADDR_FMT"; "
1912 "arp.op = 2; /* ARP reply */ "
1913 "arp.tha = arp.sha; "
1914 "arp.sha = "ETH_ADDR_FMT"; "
1915 "arp.tpa = arp.spa; "
1916 "arp.spa = "IP_FMT"; "
1917 "outport = %s; "
1918 "inport = \"\"; /* Allow sending out inport. */ "
1919 "output;",
1920 ETH_ADDR_ARGS(op->mac),
1921 ETH_ADDR_ARGS(op->mac),
1922 IP_ARGS(op->ip),
1923 op->json_key);
1924 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 90,
1925 match, actions);
abcec848
JP
1926 free(match);
1927 free(actions);
9975d7be
BP
1928
1929 /* Drop IP traffic to this router. */
1930 match = xasprintf("ip4.dst == "IP_FMT, IP_ARGS(op->ip));
1931 ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 60,
1932 match, "drop;");
1933 free(match);
1934 }
1935
1936 /* Logical router ingress table 2: IP Routing.
1937 *
1938 * A packet that arrives at this table is an IP packet that should be
0bac7164
BP
1939 * routed to the address in ip4.dst. This table sets outport to the correct
1940 * output port, eth.src to the output port's MAC address, and reg0 to the
1941 * next-hop IP address (leaving ip4.dst, the packet’s final destination,
1942 * unchanged), and advances to the next table for ARP resolution. */
9975d7be
BP
1943 HMAP_FOR_EACH (op, key_node, ports) {
1944 if (!op->nbr) {
1945 continue;
1946 }
1947
0bac7164 1948 add_route(lflows, op, op->network, op->mask, 0);
9975d7be
BP
1949 }
1950 HMAP_FOR_EACH (od, key_node, datapaths) {
1951 if (!od->nbr) {
1952 continue;
1953 }
1954
0bac7164
BP
1955 if (od->gateway && od->gateway_port) {
1956 add_route(lflows, od->gateway_port, 0, 0, od->gateway);
9975d7be
BP
1957 }
1958 }
1959 /* XXX destination unreachable */
1960
1961 /* Local router ingress table 3: ARP Resolution.
1962 *
1963 * Any packet that reaches this table is an IP packet whose next-hop IP
1964 * address is in reg0. (ip4.dst is the final destination.) This table
1965 * resolves the IP address in reg0 into an output port in outport and an
1966 * Ethernet address in eth.dst. */
1967 HMAP_FOR_EACH (op, key_node, ports) {
1968 if (op->nbr) {
509afdc3
GS
1969 /* This is a logical router port. If next-hop IP address in 'reg0'
1970 * matches ip address of this router port, then the packet is
1971 * intended to eventually be sent to this logical port. Set the
1972 * destination mac address using this port's mac address.
1973 *
1974 * The packet is still in peer's logical pipeline. So the match
1975 * should be on peer's outport. */
1976 if (op->nbr->peer) {
1977 struct ovn_port *peer = ovn_port_find(ports, op->nbr->peer);
1978 if (!peer) {
1979 continue;
1980 }
1981
1982 if (!peer->ip || !op->ip) {
1983 continue;
1984 }
1985 char *match = xasprintf("outport == %s && reg0 == "IP_FMT,
1986 peer->json_key, IP_ARGS(op->ip));
1987 char *actions = xasprintf("eth.dst = "ETH_ADDR_FMT"; "
1988 "next;", ETH_ADDR_ARGS(op->mac));
1989 ovn_lflow_add(lflows, peer->od, S_ROUTER_IN_ARP_RESOLVE,
1990 100, match, actions);
1991 free(actions);
1992 free(match);
1993 }
86e98048 1994 } else if (op->od->n_router_ports) {
9975d7be 1995 for (size_t i = 0; i < op->nbs->n_addresses; i++) {
7dc88496
NS
1996 struct lport_addresses laddrs;
1997 if (!extract_lport_addresses(op->nbs->addresses[i], &laddrs,
1998 false)) {
1999 continue;
2000 }
9975d7be 2001
7dc88496
NS
2002 for (size_t k = 0; k < laddrs.n_ipv4_addrs; k++) {
2003 ovs_be32 ip = laddrs.ipv4_addrs[k].addr;
86e98048
BP
2004 for (size_t j = 0; j < op->od->n_router_ports; j++) {
2005 /* Get the Logical_Router_Port that the Logical_Port is
2006 * connected to, as 'peer'. */
2007 const char *peer_name = smap_get(
2008 &op->od->router_ports[j]->nbs->options,
2009 "router-port");
2010 if (!peer_name) {
2011 continue;
2012 }
2013
2014 struct ovn_port *peer
2015 = ovn_port_find(ports, peer_name);
2016 if (!peer || !peer->nbr) {
2017 continue;
2018 }
2019
2020 /* Make sure that 'ip' is in 'peer''s network. */
2021 if ((ip ^ peer->network) & peer->mask) {
2022 continue;
2023 }
2024
0bac7164
BP
2025 char *match = xasprintf(
2026 "outport == %s && reg0 == "IP_FMT,
2027 peer->json_key, IP_ARGS(ip));
2028 char *actions = xasprintf("eth.dst = "ETH_ADDR_FMT"; "
2029 "next;",
2030 ETH_ADDR_ARGS(laddrs.ea));
86e98048 2031 ovn_lflow_add(lflows, peer->od,
0bac7164
BP
2032 S_ROUTER_IN_ARP_RESOLVE,
2033 100, match, actions);
86e98048
BP
2034 free(actions);
2035 free(match);
2036 break;
2037 }
9975d7be 2038 }
7dc88496
NS
2039
2040 free(laddrs.ipv4_addrs);
9975d7be
BP
2041 }
2042 }
2043 }
0bac7164
BP
2044 HMAP_FOR_EACH (od, key_node, datapaths) {
2045 if (!od->nbr) {
2046 continue;
2047 }
2048
2049 ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_RESOLVE, 0, "1",
2050 "get_arp(outport, reg0); next;");
2051 }
2052
2053 /* Local router ingress table 4: ARP request.
2054 *
2055 * In the common case where the Ethernet destination has been resolved,
2056 * this table outputs the packet (priority 100). Otherwise, it composes
2057 * and sends an ARP request (priority 0). */
2058 HMAP_FOR_EACH (od, key_node, datapaths) {
2059 if (!od->nbr) {
2060 continue;
2061 }
2062
2063 ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 100,
2064 "eth.dst == 00:00:00:00:00:00",
2065 "arp { "
2066 "eth.dst = ff:ff:ff:ff:ff:ff; "
2067 "arp.spa = reg1; "
2068 "arp.op = 1; " /* ARP request */
2069 "output; "
2070 "};");
2071 ovn_lflow_add(lflows, od, S_ROUTER_IN_ARP_REQUEST, 0, "1", "output;");
2072 }
9975d7be
BP
2073
2074 /* Logical router egress table 0: Delivery (priority 100).
2075 *
2076 * Priority 100 rules deliver packets to enabled logical ports. */
2077 HMAP_FOR_EACH (op, key_node, ports) {
2078 if (!op->nbr) {
2079 continue;
2080 }
2081
2082 if (!lrport_is_enabled(op->nbr)) {
2083 /* Drop packets to disabled logical ports (since logical flow
2084 * tables are default-drop). */
2085 continue;
2086 }
2087
2088 char *match = xasprintf("outport == %s", op->json_key);
2089 ovn_lflow_add(lflows, op->od, S_ROUTER_OUT_DELIVERY, 100,
2090 match, "output;");
2091 free(match);
2092 }
2093}
2094
2095/* Updates the Logical_Flow and Multicast_Group tables in the OVN_SB database,
2096 * constructing their contents based on the OVN_NB database. */
2097static void
2098build_lflows(struct northd_context *ctx, struct hmap *datapaths,
2099 struct hmap *ports)
2100{
2101 struct hmap lflows = HMAP_INITIALIZER(&lflows);
2102 struct hmap mcgroups = HMAP_INITIALIZER(&mcgroups);
2103
2104 build_lswitch_flows(datapaths, ports, &lflows, &mcgroups);
2105 build_lrouter_flows(datapaths, ports, &lflows);
2106
5868eb24
BP
2107 /* Push changes to the Logical_Flow table to database. */
2108 const struct sbrec_logical_flow *sbflow, *next_sbflow;
2109 SBREC_LOGICAL_FLOW_FOR_EACH_SAFE (sbflow, next_sbflow, ctx->ovnsb_idl) {
2110 struct ovn_datapath *od
2111 = ovn_datapath_from_sbrec(datapaths, sbflow->logical_datapath);
2112 if (!od) {
2113 sbrec_logical_flow_delete(sbflow);
2114 continue;
eb00399e 2115 }
eb00399e 2116
9975d7be 2117 enum ovn_datapath_type dp_type = od->nbs ? DP_SWITCH : DP_ROUTER;
880fcd14
BP
2118 enum ovn_pipeline pipeline
2119 = !strcmp(sbflow->pipeline, "ingress") ? P_IN : P_OUT;
5868eb24 2120 struct ovn_lflow *lflow = ovn_lflow_find(
880fcd14
BP
2121 &lflows, od, ovn_stage_build(dp_type, pipeline, sbflow->table_id),
2122 sbflow->priority, sbflow->match, sbflow->actions);
5868eb24
BP
2123 if (lflow) {
2124 ovn_lflow_destroy(&lflows, lflow);
2125 } else {
2126 sbrec_logical_flow_delete(sbflow);
4edcdcf4
RB
2127 }
2128 }
5868eb24
BP
2129 struct ovn_lflow *lflow, *next_lflow;
2130 HMAP_FOR_EACH_SAFE (lflow, next_lflow, hmap_node, &lflows) {
880fcd14
BP
2131 enum ovn_pipeline pipeline = ovn_stage_get_pipeline(lflow->stage);
2132 uint8_t table = ovn_stage_get_table(lflow->stage);
2133
5868eb24
BP
2134 sbflow = sbrec_logical_flow_insert(ctx->ovnsb_txn);
2135 sbrec_logical_flow_set_logical_datapath(sbflow, lflow->od->sb);
9975d7be
BP
2136 sbrec_logical_flow_set_pipeline(
2137 sbflow, pipeline == P_IN ? "ingress" : "egress");
880fcd14 2138 sbrec_logical_flow_set_table_id(sbflow, table);
5868eb24
BP
2139 sbrec_logical_flow_set_priority(sbflow, lflow->priority);
2140 sbrec_logical_flow_set_match(sbflow, lflow->match);
2141 sbrec_logical_flow_set_actions(sbflow, lflow->actions);
091e3af9 2142
880fcd14
BP
2143 const struct smap ids = SMAP_CONST1(&ids, "stage-name",
2144 ovn_stage_to_str(lflow->stage));
aaf881c6 2145 sbrec_logical_flow_set_external_ids(sbflow, &ids);
091e3af9 2146
5868eb24 2147 ovn_lflow_destroy(&lflows, lflow);
eb00399e 2148 }
5868eb24
BP
2149 hmap_destroy(&lflows);
2150
2151 /* Push changes to the Multicast_Group table to database. */
2152 const struct sbrec_multicast_group *sbmc, *next_sbmc;
2153 SBREC_MULTICAST_GROUP_FOR_EACH_SAFE (sbmc, next_sbmc, ctx->ovnsb_idl) {
2154 struct ovn_datapath *od = ovn_datapath_from_sbrec(datapaths,
2155 sbmc->datapath);
2156 if (!od) {
2157 sbrec_multicast_group_delete(sbmc);
2158 continue;
2159 }
eb00399e 2160
5868eb24
BP
2161 struct multicast_group group = { .name = sbmc->name,
2162 .key = sbmc->tunnel_key };
2163 struct ovn_multicast *mc = ovn_multicast_find(&mcgroups, od, &group);
2164 if (mc) {
2165 ovn_multicast_update_sbrec(mc, sbmc);
2166 ovn_multicast_destroy(&mcgroups, mc);
2167 } else {
2168 sbrec_multicast_group_delete(sbmc);
2169 }
2170 }
2171 struct ovn_multicast *mc, *next_mc;
2172 HMAP_FOR_EACH_SAFE (mc, next_mc, hmap_node, &mcgroups) {
2173 sbmc = sbrec_multicast_group_insert(ctx->ovnsb_txn);
2174 sbrec_multicast_group_set_datapath(sbmc, mc->datapath->sb);
2175 sbrec_multicast_group_set_name(sbmc, mc->group->name);
2176 sbrec_multicast_group_set_tunnel_key(sbmc, mc->group->key);
2177 ovn_multicast_update_sbrec(mc, sbmc);
2178 ovn_multicast_destroy(&mcgroups, mc);
4edcdcf4 2179 }
5868eb24 2180 hmap_destroy(&mcgroups);
4edcdcf4 2181}
5868eb24 2182\f
4edcdcf4 2183static void
331e7aef 2184ovnnb_db_run(struct northd_context *ctx)
4edcdcf4 2185{
331e7aef
NS
2186 if (!ctx->ovnsb_txn) {
2187 return;
2188 }
5868eb24
BP
2189 struct hmap datapaths, ports;
2190 build_datapaths(ctx, &datapaths);
2191 build_ports(ctx, &datapaths, &ports);
2192 build_lflows(ctx, &datapaths, &ports);
2193
2194 struct ovn_datapath *dp, *next_dp;
2195 HMAP_FOR_EACH_SAFE (dp, next_dp, key_node, &datapaths) {
2196 ovn_datapath_destroy(&datapaths, dp);
2197 }
2198 hmap_destroy(&datapaths);
2199
2200 struct ovn_port *port, *next_port;
2201 HMAP_FOR_EACH_SAFE (port, next_port, key_node, &ports) {
2202 ovn_port_destroy(&ports, port);
2203 }
2204 hmap_destroy(&ports);
ac0630a2
RB
2205}
2206
f93818dd
RB
2207/*
2208 * The only change we get notified about is if the 'chassis' column of the
dcda6e0d
BP
2209 * 'Port_Binding' table changes. When this column is not empty, it means we
2210 * need to set the corresponding logical port as 'up' in the northbound DB.
f93818dd 2211 */
ac0630a2 2212static void
331e7aef 2213ovnsb_db_run(struct northd_context *ctx)
ac0630a2 2214{
331e7aef
NS
2215 if (!ctx->ovnnb_txn) {
2216 return;
2217 }
fc3113bc 2218 struct hmap lports_hmap;
5868eb24
BP
2219 const struct sbrec_port_binding *sb;
2220 const struct nbrec_logical_port *nb;
fc3113bc
RB
2221
2222 struct lport_hash_node {
2223 struct hmap_node node;
5868eb24 2224 const struct nbrec_logical_port *nb;
fc3113bc 2225 } *hash_node, *hash_node_next;
f93818dd 2226
fc3113bc 2227 hmap_init(&lports_hmap);
f93818dd 2228
5868eb24 2229 NBREC_LOGICAL_PORT_FOR_EACH(nb, ctx->ovnnb_idl) {
fc3113bc 2230 hash_node = xzalloc(sizeof *hash_node);
5868eb24
BP
2231 hash_node->nb = nb;
2232 hmap_insert(&lports_hmap, &hash_node->node, hash_string(nb->name, 0));
fc3113bc
RB
2233 }
2234
5868eb24
BP
2235 SBREC_PORT_BINDING_FOR_EACH(sb, ctx->ovnsb_idl) {
2236 nb = NULL;
fc3113bc 2237 HMAP_FOR_EACH_WITH_HASH(hash_node, node,
5868eb24
BP
2238 hash_string(sb->logical_port, 0),
2239 &lports_hmap) {
2240 if (!strcmp(sb->logical_port, hash_node->nb->name)) {
2241 nb = hash_node->nb;
fc3113bc
RB
2242 break;
2243 }
f93818dd
RB
2244 }
2245
5868eb24 2246 if (!nb) {
dcda6e0d 2247 /* The logical port doesn't exist for this port binding. This can
2e2762d4 2248 * happen under normal circumstances when ovn-northd hasn't gotten
dcda6e0d 2249 * around to pruning the Port_Binding yet. */
f93818dd
RB
2250 continue;
2251 }
2252
5868eb24 2253 if (sb->chassis && (!nb->up || !*nb->up)) {
f93818dd 2254 bool up = true;
5868eb24
BP
2255 nbrec_logical_port_set_up(nb, &up, 1);
2256 } else if (!sb->chassis && (!nb->up || *nb->up)) {
f93818dd 2257 bool up = false;
5868eb24 2258 nbrec_logical_port_set_up(nb, &up, 1);
f93818dd
RB
2259 }
2260 }
fc3113bc
RB
2261
2262 HMAP_FOR_EACH_SAFE(hash_node, hash_node_next, node, &lports_hmap) {
2263 hmap_remove(&lports_hmap, &hash_node->node);
2264 free(hash_node);
2265 }
2266 hmap_destroy(&lports_hmap);
ac0630a2
RB
2267}
2268\f
45f98d4c 2269
60bdd011 2270static char *default_nb_db_;
45f98d4c 2271
ac0630a2 2272static const char *
60bdd011 2273default_nb_db(void)
ac0630a2 2274{
60bdd011
RM
2275 if (!default_nb_db_) {
2276 default_nb_db_ = xasprintf("unix:%s/ovnnb_db.sock", ovs_rundir());
ac0630a2 2277 }
60bdd011
RM
2278 return default_nb_db_;
2279}
2280
2281static char *default_sb_db_;
2282
2283static const char *
2284default_sb_db(void)
2285{
2286 if (!default_sb_db_) {
2287 default_sb_db_ = xasprintf("unix:%s/ovnsb_db.sock", ovs_rundir());
2288 }
2289 return default_sb_db_;
ac0630a2
RB
2290}
2291
2292static void
2293parse_options(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
2294{
2295 enum {
67d9b930 2296 DAEMON_OPTION_ENUMS,
ac0630a2
RB
2297 VLOG_OPTION_ENUMS,
2298 };
2299 static const struct option long_options[] = {
ec78987f 2300 {"ovnsb-db", required_argument, NULL, 'd'},
ac0630a2
RB
2301 {"ovnnb-db", required_argument, NULL, 'D'},
2302 {"help", no_argument, NULL, 'h'},
2303 {"options", no_argument, NULL, 'o'},
2304 {"version", no_argument, NULL, 'V'},
67d9b930 2305 DAEMON_LONG_OPTIONS,
ac0630a2
RB
2306 VLOG_LONG_OPTIONS,
2307 STREAM_SSL_LONG_OPTIONS,
2308 {NULL, 0, NULL, 0},
2309 };
2310 char *short_options = ovs_cmdl_long_options_to_short_options(long_options);
2311
2312 for (;;) {
2313 int c;
2314
2315 c = getopt_long(argc, argv, short_options, long_options, NULL);
2316 if (c == -1) {
2317 break;
2318 }
2319
2320 switch (c) {
67d9b930 2321 DAEMON_OPTION_HANDLERS;
ac0630a2
RB
2322 VLOG_OPTION_HANDLERS;
2323 STREAM_SSL_OPTION_HANDLERS;
2324
2325 case 'd':
ec78987f 2326 ovnsb_db = optarg;
ac0630a2
RB
2327 break;
2328
2329 case 'D':
2330 ovnnb_db = optarg;
2331 break;
2332
2333 case 'h':
2334 usage();
2335 exit(EXIT_SUCCESS);
2336
2337 case 'o':
2338 ovs_cmdl_print_options(long_options);
2339 exit(EXIT_SUCCESS);
2340
2341 case 'V':
2342 ovs_print_version(0, 0);
2343 exit(EXIT_SUCCESS);
2344
2345 default:
2346 break;
2347 }
2348 }
2349
ec78987f 2350 if (!ovnsb_db) {
60bdd011 2351 ovnsb_db = default_sb_db();
ac0630a2
RB
2352 }
2353
2354 if (!ovnnb_db) {
60bdd011 2355 ovnnb_db = default_nb_db();
ac0630a2
RB
2356 }
2357
2358 free(short_options);
2359}
2360
5868eb24
BP
2361static void
2362add_column_noalert(struct ovsdb_idl *idl,
2363 const struct ovsdb_idl_column *column)
2364{
2365 ovsdb_idl_add_column(idl, column);
2366 ovsdb_idl_omit_alert(idl, column);
2367}
2368
ac0630a2
RB
2369int
2370main(int argc, char *argv[])
2371{
ac0630a2 2372 int res = EXIT_SUCCESS;
7b303ff9
AW
2373 struct unixctl_server *unixctl;
2374 int retval;
2375 bool exiting;
ac0630a2
RB
2376
2377 fatal_ignore_sigpipe();
2378 set_program_name(argv[0]);
485f0696 2379 service_start(&argc, &argv);
ac0630a2 2380 parse_options(argc, argv);
67d9b930 2381
e91b927d 2382 daemonize_start(false);
7b303ff9
AW
2383
2384 retval = unixctl_server_create(NULL, &unixctl);
2385 if (retval) {
2386 exit(EXIT_FAILURE);
2387 }
2388 unixctl_command_register("exit", "", 0, 0, ovn_northd_exit, &exiting);
2389
2390 daemonize_complete();
67d9b930 2391
ac0630a2 2392 nbrec_init();
ec78987f 2393 sbrec_init();
ac0630a2
RB
2394
2395 /* We want to detect all changes to the ovn-nb db. */
331e7aef
NS
2396 struct ovsdb_idl_loop ovnnb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
2397 ovsdb_idl_create(ovnnb_db, &nbrec_idl_class, true, true));
2398
2399 struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
2400 ovsdb_idl_create(ovnsb_db, &sbrec_idl_class, false, true));
2401
2402 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_logical_flow);
2403 add_column_noalert(ovnsb_idl_loop.idl,
2404 &sbrec_logical_flow_col_logical_datapath);
2405 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_pipeline);
2406 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_table_id);
2407 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_priority);
2408 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_match);
2409 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_logical_flow_col_actions);
2410
2411 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_multicast_group);
2412 add_column_noalert(ovnsb_idl_loop.idl,
2413 &sbrec_multicast_group_col_datapath);
2414 add_column_noalert(ovnsb_idl_loop.idl,
2415 &sbrec_multicast_group_col_tunnel_key);
2416 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_name);
2417 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_multicast_group_col_ports);
2418
2419 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding);
2420 add_column_noalert(ovnsb_idl_loop.idl,
2421 &sbrec_datapath_binding_col_tunnel_key);
2422 add_column_noalert(ovnsb_idl_loop.idl,
2423 &sbrec_datapath_binding_col_external_ids);
2424
2425 ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding);
2426 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_datapath);
2427 add_column_noalert(ovnsb_idl_loop.idl,
2428 &sbrec_port_binding_col_logical_port);
2429 add_column_noalert(ovnsb_idl_loop.idl,
2430 &sbrec_port_binding_col_tunnel_key);
2431 add_column_noalert(ovnsb_idl_loop.idl,
2432 &sbrec_port_binding_col_parent_port);
2433 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_tag);
2434 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_type);
2435 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_options);
2436 add_column_noalert(ovnsb_idl_loop.idl, &sbrec_port_binding_col_mac);
2437 ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_port_binding_col_chassis);
2438
2439 /* Main loop. */
7b303ff9
AW
2440 exiting = false;
2441 while (!exiting) {
331e7aef
NS
2442 struct northd_context ctx = {
2443 .ovnnb_idl = ovnnb_idl_loop.idl,
2444 .ovnnb_txn = ovsdb_idl_loop_run(&ovnnb_idl_loop),
2445 .ovnsb_idl = ovnsb_idl_loop.idl,
2446 .ovnsb_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
2447 };
ac0630a2 2448
8c0fae89
NS
2449 ovnnb_db_run(&ctx);
2450 ovnsb_db_run(&ctx);
f93818dd 2451
331e7aef
NS
2452 unixctl_server_run(unixctl);
2453 unixctl_server_wait(unixctl);
2454 if (exiting) {
2455 poll_immediate_wake();
ac0630a2 2456 }
331e7aef
NS
2457 ovsdb_idl_loop_commit_and_wait(&ovnnb_idl_loop);
2458 ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
ac0630a2 2459
331e7aef 2460 poll_block();
485f0696
GS
2461 if (should_service_stop()) {
2462 exiting = true;
2463 }
ac0630a2
RB
2464 }
2465
7b303ff9 2466 unixctl_server_destroy(unixctl);
331e7aef
NS
2467 ovsdb_idl_loop_destroy(&ovnnb_idl_loop);
2468 ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
485f0696 2469 service_stop();
ac0630a2 2470
60bdd011
RM
2471 free(default_nb_db_);
2472 free(default_sb_db_);
ac0630a2
RB
2473 exit(res);
2474}
7b303ff9
AW
2475
2476static void
2477ovn_northd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED,
2478 const char *argv[] OVS_UNUSED, void *exiting_)
2479{
2480 bool *exiting = exiting_;
2481 *exiting = true;
2482
2483 unixctl_command_reply(conn, NULL);
2484}