From patchwork Sat Mar 27 00:31:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459068 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6ftM0Hzyz9sCD for ; Sat, 27 Mar 2021 11:32:10 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 15EFE40650; Sat, 27 Mar 2021 00:32:07 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id lTl1FOc65ELW; Sat, 27 Mar 2021 00:32:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTP id 0691040636; Sat, 27 Mar 2021 00:32:04 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 7FE30C0015; Sat, 27 Mar 2021 00:32:02 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 6FC39C000A for ; Sat, 27 Mar 2021 00:32:01 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 4FDA5418AB for ; Sat, 27 Mar 2021 00:32:01 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ln348DuBqrkJ for ; Sat, 27 Mar 2021 00:31:59 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp4.osuosl.org (Postfix) with ESMTPS id A6E1241842 for ; Sat, 27 Mar 2021 00:31:58 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id DE6D9FF804; Sat, 27 Mar 2021 00:31:55 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:27 -0700 Message-Id: <20210327003147.2955790-2-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Ben Pfaff Subject: [ovs-dev] [PATCH ovn 01/21] ovn-nbctl: Improve manpage. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" This rearranges the manpage into a more logical order, documents some options that weren't documented, adds some sections such as Environment and Exit Status that a manpage should have, puts the headings at reasonable levels instead of all at the top level, and adds a little more explanatory text in a few places. Signed-off-by: Ben Pfaff --- utilities/ovn-nbctl.8.xml | 670 ++++++++++++++++++++++---------------- 1 file changed, 392 insertions(+), 278 deletions(-) diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml index 03d47dba5b72..39f9381fdaae 100644 --- a/utilities/ovn-nbctl.8.xml +++ b/utilities/ovn-nbctl.8.xml @@ -7,9 +7,327 @@

ovn-nbctl [options] command [arg...]

Description

-

This utility can be used to manage the OVN northbound database.

-

General Commands

+

+ The ovn-nbctl program configures the + OVN_Northbound database by providing a high-level interface + to its configuration database. See ovn-nb(5) for + comprehensive documentation of the database schema. +

+ +

+ ovn-nbctl connects to an ovsdb-server process + that maintains an OVN_Northbound configuration database. Using this + connection, it queries and possibly applies changes to the database, + depending on the supplied commands. +

+ +

+ ovn-nbctl can perform any number of commands in a single + run, implemented as a single atomic transaction against the database. +

+ +

+ The ovn-nbctl command line begins with global options (see + OPTIONS below for details). The global options are followed + by one or more commands. Each command should begin with -- + by itself as a command-line argument, to separate it from the following + commands. (The -- before the first command is optional.) + The command itself starts with command-specific options, if any, followed + by the command name and any arguments. +

+ +

Daemon Mode

+ +

+ When it is invoked in the most ordinary way, ovn-nbctl + connects to an OVSDB server that hosts the northbound database, retrieves + a partial copy of the database that is complete enough to do its work, + sends a transaction request to the server, and receives and processes the + server's reply. In common interactive use, this is fine, but if the + database is large, the step in which ovn-nbctl retrieves a + partial copy of the database can take a long time, which yields poor + performance overall. +

+ +

+ To improve performance in such a case, ovn-nbctl offers a + "daemon mode," in which the user first starts ovn-nbctl + running in the background and afterward uses the daemon to execute + operations. Over several ovn-nbctl command invocations, + this performs better overall because it retrieves a copy of the database + only once at the beginning, not once per program run. +

+ +

+ Use the --detach option to start an ovn-nbctl + daemon. With this option, ovn-nbctl prints the name of a + control socket to stdout. The client should save this name in + environment variable OVN_NB_DAEMON. Under the Bourne shell + this might be done like this: +

+ +
+      export OVN_NB_DAEMON=$(ovn-nbctl --pidfile --detach)
+    
+ +

+ When OVN_NB_DAEMON is set, ovn-nbctl + automatically and transparently uses the daemon to execute its commands. +

+ +

+ When the daemon is no longer needed, kill it and unset the environment + variable, e.g.: +

+ +
+      kill $(cat $OVN_RUNDIR/ovn-nbctl.pid)
+      unset OVN_NB_DAEMON
+    
+ +

+ When using daemon mode, an alternative to the OVN_NB_DAEMON + environment variable is to specify a path for the Unix socket. When + starting the ovn-nbctl daemon, specify the -u option with a + full path to the location of the socket file. Here is an exmple: +

+ +
+      ovn-nbctl --detach -u /tmp/mysock.ctl
+    
+ +

+ Then to connect to the running daemon, use the -u option + with the full path to the socket created when the daemon was started: +

+ +
+      ovn-nbctl -u /tmp/mysock.ctl show
+    
+ +

+ Daemon mode is experimental. +

+ +

Daemon Commands

+ +

+ Daemon mode is internally implemented using the same mechanism used by + ovs-appctl. One may also use ovs-appctl + directly with the following commands: +

+ +
+
+ run [options] command + [arg...] [-- [options] + command [arg...] ...] +
+
+ Instructs the daemon process to run one or more ovn-nbctl + commands described above and reply with the results of running these + commands. Accepts the --no-wait, --wait, + --timeout, --dry-run, --oneline, + and the options described under Table Formatting Options + in addition to the the command-specific options. +
+ +
exit
+
Causes ovn-nbctl to gracefully terminate.
+
+ +

Options

+ +

+ The options listed below affect the behavior of ovn-nbctl as + a whole. Some individual commands also accept their own options, which + are given just before the command name. If the first command on the + command line has options, then those options must be separated from the + global options by --. +

+ +

+ ovn-nbctl also accepts options from the + OVN_NBCTL_OPTIONS environment variable, in the same format as + on the command line. Options from the command line override those in the + environment. +

+ +
+
--no-wait | --wait=none
+
--wait=sb
+
--wait=hv
+ +
+

+ These options control whether and how ovn-nbctl waits + for the OVN system to become up-to-date with changes made in an + ovn-nbctl invocation. +

+ +

+ By default, or if --no-wait or --wait=none, + ovn-nbctl exits immediately after confirming that + changes have been committed to the northbound database, without + waiting. +

+ +

+ With --wait=sb, before ovn-nbctl exits, it + waits for ovn-northd to bring the southbound database + up-to-date with the northbound database updates. +

+ +

+ With --wait=hv, before ovn-nbctl exits, it + additionally waits for all OVN chassis (hypervisors and gateways) to + become up-to-date with the northbound database updates. (This can + become an indefinite wait if any chassis is malfunctioning.) +

+ +

+ Ordinarily, --wait=sb or --wait=hv only + waits for changes by the current ovn-nbctl invocation to + take effect. This means that, if none of the commands supplied to + ovn-nbctl change the database, then the command does not + wait at all. Use the sync command to override this + behavior. +

+
+ +
--db database
+
+ The OVSDB database remote to contact. If the OVN_NB_DB + environment variable is set, its value is used as the default. + Otherwise, the default is unix:@RUNDIR@/ovnnb_db.sock, but + this default is unlikely to be useful outside of single-machine OVN + test environments. +
+ +
--leader-only
+
--no-leader-only
+
+ By default, or with --leader-only, when the database + server is a clustered database, ovn-nbctl will avoid + servers other than the cluster leader. This ensures that any data that + ovn-nbctl reads and reports is up-to-date. With + --no-leader-only, ovn-nbctl will use any + server in the cluster, which means that for read-only transactions it + can report and act on stale data (transactions that modify the database + are always serialized even with --no-leader-only). Refer + to Understanding Cluster Consistency in + ovsdb(7) for more information. +
+ +
--shuffle-remotes
+
--no-shuffle-remotes
+
+ By default, or with --shuffle-remotes, when there are + multiple remotes specified in the OVSDB connection string specified by + --db or the OVN_NB_DB environment variable, the + order of the remotes will be shuffled before the client tries to + connect. The remotes will be shuffled only once to a new order before + the first connection attempt. The following retries, if any, will + follow the same new order. The default behavior is to make sure + clients of a clustered database can distribute evenly to all memembers + of the cluster. With --no-shuffle-remotes, + ovn-nbctl will use the original order specified in the + connection string to connect. This allows user to specify the + preferred order, which is particularly useful for testing. +
+ +
--no-syslog
+
+

+ By default, ovn-nbctl logs its arguments and the details + of any changes that it makes to the system log. This option disables + this logging. +

+ +

+ This option is equivalent to + --verbose=nbctl:syslog:warn. +

+
+ +
--oneline
+
+ Modifies the output format so that the output for each command is + printed on a single line. New-line characters that would otherwise + separate lines are printed as \fB\\n\fR, and any instances of \fB\\\fR + that would otherwise appear in the output are doubled. Prints a blank + line for each command that has no output. This option does not affect + the formatting of output from the list or + find commands; see Table Formatting Options + below. +
+ +
--dry-run
+
+ Prevents ovn-nbctl from actually modifying the database. +
+ +
-t secs
+
--timeout=secs
+
+ By default, or with a secs of 0, + ovn-nbctl waits forever for a response from the database. + This option limits runtime to approximately secs seconds. + If the timeout expires, ovn-nbctl will exit with a + SIGALRM signal. (A timeout would normally happen only if + the database cannot be contacted, or if the system is overloaded.) +
+ +
--print-wait-time
+
+ When --wait is specified, the option + --print-wait-time can be used to print the time spent on + waiting, depending on the value specified in --wait + option. If --wait=sb is specified, it prints "ovn-northd + delay before processing", which is the time between the Northbound DB + update by the command and the moment when ovn-northd + starts processing the update, and "ovn-northd completion", which is the + time between the Northbound DB update and the moment when + ovn-northd completes the Southbound DB updating + successfully. If --wait=hv is specified, in addition to + the above information, it also prints "ovn-controller(s) completion", + which is the time between the Northbound DB update and the moment when + the slowest hypervisor finishes processing the update. +
+
+ +

Daemon Options

+ + +

Logging options

+ + +

Table Formatting Options

+ These options control the format of output from the list and + find commands. + + +

PKI Options

+

+ PKI configuration is required to use SSL for the connection to the + database. +

+ + + +

Other Options

+ + + +

Commands

+ +

+ The following sections describe the commands that ovn-nbctl + supports. +

+ +

General Commands

init
@@ -28,7 +346,7 @@
-

Logical Switch Commands

+

Logical Switch Commands

ls-add
@@ -74,7 +392,7 @@
-

ACL Commands

+

ACL Commands

These commands operates on ACL objects for a given entity. The entity can be either a logical switch or a port group. @@ -127,7 +445,7 @@ -

Logical Switch QoS Rule Commands

+

Logical Switch QoS Rule Commands

[--may-exist] qos-add switch direction priority match [dscp=dscp] [rate=rate [burst=burst]]
@@ -181,7 +499,7 @@
-

Meter Commands

+

Meter Commands

meter-add name action rate unit [burst]
@@ -234,7 +552,7 @@
-

Logical Switch Port Commands

+

Logical Switch Port Commands

[--may-exist] lsp-add switch port
@@ -490,7 +808,7 @@
-

Forwarding Group Commands

+

Forwarding Group Commands

[--liveness]fwd-group-add group switch vip vmac ports
@@ -528,7 +846,7 @@ be listed.
-

Logical Router Commands

+

Logical Router Commands

lr-add
@@ -574,7 +892,7 @@
-

Logical Router Port Commands

+

Logical Router Port Commands

[--may-exist] lrp-add router port mac network... [peer=peer]
@@ -654,7 +972,7 @@
-

Logical Router Static Route Commands

+

Logical Router Static Route Commands

[--may-exist] [--policy=POLICY] @@ -745,7 +1063,7 @@
-

Logical Router Policy Commands

+

Logical Router Policy Commands

[--may-exist]lr-policy-add @@ -817,7 +1135,7 @@
-

NAT Commands

+

NAT Commands

[--may-exist] [--stateless]lr-nat-add router type external_ip logical_ip [logical_port external_mac]
@@ -914,7 +1232,7 @@
-

Load Balancer Commands

+

Load Balancer Commands

[--may-exist | --add-duplicate | --reject | --event] lb-add lb vip ips [protocol]
@@ -1038,7 +1356,7 @@
-

DHCP Options commands

+

DHCP Options commands

dhcp-options-create cidr [key=value]
@@ -1068,7 +1386,7 @@
-

Port Group commands

+

Port Group commands

pg-add group [port]...
@@ -1090,7 +1408,7 @@
-

HA Chassis Group commands

+

HA Chassis Group commands

ha-chassis-group-add group
@@ -1131,38 +1449,7 @@
-

Database Commands

-

These commands query and modify the contents of ovsdb tables. - They are a slight abstraction of the ovsdb interface and - as such they operate at a lower level than other ovn-nbctl commands.

-

Identifying Tables, Records, and Columns

-

Each of these commands has a table parameter to identify a table - within the database. Many of them also take a record parameter - that identifies a particular record within a table. The record - parameter may be the UUID for a record, which may be abbreviated to its - first 4 (or more) hex digits, as long as that is unique. Many tables offer - additional ways to identify records. Some commands also take - column parameters that identify a particular field within the - records in a table.

- -

- For a list of tables and their columns, see ovn-nb(5) or - see the table listing from the --help option. -

- -

- Record names must be specified in full and with correct capitalization, - except that UUIDs may be abbreviated to their first 4 (or more) hex - digits, as long as that is unique within the table. Names of tables and - columns are not case-sensitive, and - and _ are - treated interchangeably. Unique abbreviations of table and column names - are acceptable, e.g. d or dhcp is sufficient - to identify the DHCP_Options table. -

- - - -

Synchronization Commands

+

Synchronization Commands

sync
@@ -1178,7 +1465,15 @@
-

Remote Connectivity Commands

+

Remote Connectivity Commands

+

+ These commands manipulate the connections column in the + NB_Global table and rows in the Connection + table. When ovsdb-server is configured to use the + connections column for OVSDB connections, this allows the + administrator to use ovn-nbctl to configure database + connections. +

get-connection
@@ -1198,7 +1493,7 @@
-

SSL Configuration Commands

+

SSL Configuration Commands

get-ssl
@@ -1218,258 +1513,77 @@
-

Daemon Mode

- -

- When it is invoked in the most ordinary way, ovn-nbctl - connects to an OVSDB server that hosts the northbound database, retrieves - a partial copy of the database that is complete enough to do its work, - sends a transaction request to the server, and receives and processes the - server's reply. In common interactive use, this is fine, but if the - database is large, the step in which ovn-nbctl retrieves a - partial copy of the database can take a long time, which yields poor - performance overall. -

- -

- To improve performance in such a case, ovn-nbctl offers a - "daemon mode," in which the user first starts ovn-nbctl - running in the background and afterward uses the daemon to execute - operations. Over several ovn-nbctl command invocations, - this performs better overall because it retrieves a copy of the database - only once at the beginning, not once per program run. -

- +

Database Commands

- Use the --detach option to start an ovn-nbctl - daemon. With this option, ovn-nbctl prints the name of a - control socket to stdout. The client should save this name in - environment variable OVN_NB_DAEMON. Under the Bourne shell - this might be done like this: + These commands query and modify the contents of ovsdb + tables. They are a slight abstraction of the ovsdb + interface and as such they operate at a lower level than other + ovn-nbctl commands.

-
-      export OVN_NB_DAEMON=$(ovn-nbctl --pidfile --detach)
-    
- -

- When OVN_NB_DAEMON is set, ovn-nbctl - automatically and transparently uses the daemon to execute its commands. -

+

Identifying Tables, Records, and Columns

- When the daemon is no longer needed, kill it and unset the environment - variable, e.g.: + Each of these commands has a table parameter to identify a + table within the database. Many of them also take a record + parameter that identifies a particular record within a table. The + record parameter may be the UUID for a record, which may be + abbreviated to its first 4 (or more) hex digits, as long as that is + unique. Many tables offer additional ways to identify records. Some + commands also take column parameters that identify a + particular field within the records in a table.

-
-      kill $(cat $OVN_RUNDIR/ovn-nbctl.pid)
-      unset OVN_NB_DAEMON
-    
-

- When using daemon mode, an alternative to the OVN_NB_DAEMON environment - variable is to specify a path for the Unix socket. When starting the - ovn-nbctl daemon, specify the -u option with a full path to - the location of the socket file. Here is an exmple: + For a list of tables and their columns, see ovn-nb(5) or + see the table listing from the --help option.

-
-      ovn-nbctl --detach -u /tmp/mysock.ctl
-    
-

- Then to connect to the running daemon, use the -u option - with the full path to the socket created when the daemon was started: -

- -
-      ovn-nbctl -u /tmp/mysock.ctl show
-    
- -

- Daemon mode is experimental. + Record names must be specified in full and with correct capitalization, + except that UUIDs may be abbreviated to their first 4 (or more) hex + digits, as long as that is unique within the table. Names of tables and + columns are not case-sensitive, and - and _ are + treated interchangeably. Unique abbreviations of table and column names + are acceptable, e.g. d or dhcp is sufficient + to identify the DHCP_Options table.

-

Daemon Commands

+ -

- Daemon mode is internally implemented using the same mechanism used by - ovs-appctl. One may also use ovs-appctl - directly with the following commands: -

+

Environment

-
- run [options] command - [arg...] [-- [options] - command [arg...] ...] -
+
OVN_NB_DAEMON
- Instructs the daemon process to run one or more ovn-nbctl - commands described above and reply with the results of running these - commands. Accepts the --no-wait, --wait, - --timeout, --dry-run, --oneline, - and the options described under Table Formatting Options - in addition to the the command-specific options. + If set, this should name the Unix domain socket for an + ovn-nbctl server process. See Daemon Mode, + above, for more information.
-
exit
-
Causes ovn-nbctl to gracefully terminate.
-
- -

Options

- -
-
--no-wait | --wait=none
-
--wait=sb
-
--wait=hv
- +
OVN_NBCTL_OPTIONS
-

- These options control whether and how ovn-nbctl waits - for the OVN system to become up-to-date with changes made in an - ovn-nbctl invocation. -

- -

- By default, or if --no-wait or --wait=none, - ovn-nbctl exits immediately after confirming that - changes have been committed to the northbound database, without - waiting. -

- -

- With --wait=sb, before ovn-nbctl exits, it - waits for ovn-northd to bring the southbound database - up-to-date with the northbound database updates. -

- -

- With --wait=hv, before ovn-nbctl exits, it - additionally waits for all OVN chassis (hypervisors and gateways) to - become up-to-date with the northbound database updates. (This can - become an indefinite wait if any chassis is malfunctioning.) -

- -

- Ordinarily, --wait=sb or --wait=hv only - waits for changes by the current ovn-nbctl invocation to - take effect. This means that, if none of the commands supplied to - ovn-nbctl change the database, then the command does not - wait at all. Use the sync command to override this - behavior. -

+ If set, a set of options for ovn-nbctl to apply + automatically, in the same form as on the command line.
-
--print-wait-time
-
- When --wait is specified, the option - --print-wait-time can be used to print the time spent on - waiting, depending on the value specified in --wait option. - If --wait=sb is specified, it prints "ovn-northd delay - before processing", which is the time between the Northbound DB update by - the command and the moment when ovn-northd starts - processing the update, and "ovn-northd completion", which is the time - between the Northbound DB update and the moment when - ovn-northd completes the Southbound DB updating - successfully. If --wait=hv is specified, in addition to the - above information, it also prints "ovn-controller(s) completion", which - is the time between the Northbound DB update and the moment when the - slowest hypervisor finishes processing the update. -
- -
--db database
-
- The OVSDB database remote to contact. If the OVN_NB_DB - environment variable is set, its value is used as the default. - Otherwise, the default is unix:@RUNDIR@/ovnnb_db.sock, but this - default is unlikely to be useful outside of single-machine OVN test - environments. -
- -
--leader-only
-
--no-leader-only
-
- By default, or with --leader-only, when the database server - is a clustered database, ovn-nbctl will avoid servers other - than the cluster leader. This ensures that any data that - ovn-nbctl reads and reports is up-to-date. With - --no-leader-only, ovn-nbctl will use any server - in the cluster, which means that for read-only transactions it can report - and act on stale data (transactions that modify the database are always - serialized even with --no-leader-only). Refer to - Understanding Cluster Consistency in ovsdb(7) - for more information. -
- -
--shuffle-remotes
-
--no-shuffle-remotes
-
- By default, or with --shuffle-remotes, when there are - multiple remotes specified in the OVSDB connection string specified by - --db or the OVN_NB_DB environment variable, - the order of the remotes will be shuffled before the client tries to - connect. The remotes will be shuffled only once to a new order before - the first connection attempt. The following retries, if any, will - follow the same new order. The default behavior is to make sure - clients of a clustered database can distribute evenly to all memembers - of the cluster. With --no-shuffle-remotes, - ovn-nbctl will use the original order specified in the - connection string to connect. This allows user to specify the - preferred order, which is particularly useful for testing. -
- -
OVN_NBCTL_OPTIONS
-
-

- User can set one or more OVN_NBCTL_OPTIONS options in - environment variable. Under the Bourne shell this might be - done like this: -

- -
-          OVN_NBCTL_OPTIONS="--db=unix:nb1.ovsdb --no-leader-only"
-        
- -

- When OVN_NBCTL_OPTIONS is set, ovn-nbctl - automatically and transparently uses the environment variable to - execute its commands. However user can still over-ride environment - options by passing different in cli. -

- -

- When the environment variable is no longer needed, unset it, e.g.: -

- -
-          unset OVN_NBCTL_OPTIONS
-        
-
+
OVN_NB_DB
+
+ If set, the default database to contact when the --db + option is not used. +
-

Daemon Options

- - -

Logging options

- - -

Table Formatting Options

- These options control the format of output from the list and - find commands. - - -

PKI Options

-

- PKI configuration is required to use SSL for the connection to the - database. -

- - +

Exit Status

+
+
0
+
Successful program execution.
-

Other Options

+
1
+
Usage, syntax, or network error.
+
- +

See Also

+ ovn-nb(5). From patchwork Sat Mar 27 00:31:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459070 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6ftW5Ph9z9sCD for ; Sat, 27 Mar 2021 11:32:19 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 82B27418D6; Sat, 27 Mar 2021 00:32:17 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id VCOV_CD-ER1w; Sat, 27 Mar 2021 00:32:09 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTP id EF9FF418CC; Sat, 27 Mar 2021 00:32:07 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B81CFC000D; Sat, 27 Mar 2021 00:32:07 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0FD23C0015 for ; Sat, 27 Mar 2021 00:32:06 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 0128E84D7E for ; Sat, 27 Mar 2021 00:32:05 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 5Mace5durpdO for ; Sat, 27 Mar 2021 00:32:01 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id BAC8984CEE for ; Sat, 27 Mar 2021 00:32:00 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 9FBD0FF805; Sat, 27 Mar 2021 00:31:57 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:28 -0700 Message-Id: <20210327003147.2955790-3-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Ben Pfaff Subject: [ovs-dev] [PATCH ovn 02/21] ovn-nbctl: Refactor into infrastructure and northbound details. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" In an upcoming commit, this will allow adding daemon mode to ovn-sbctl without having a lot of duplicated code. Signed-off-by: Ben Pfaff --- utilities/automake.mk | 5 +- utilities/ovn-dbctl.c | 1214 ++++++++++++++++++++++++++++++++++++ utilities/ovn-dbctl.h | 60 ++ utilities/ovn-nbctl.c | 1361 ++++------------------------------------- 4 files changed, 1411 insertions(+), 1229 deletions(-) create mode 100644 utilities/ovn-dbctl.c create mode 100644 utilities/ovn-dbctl.h diff --git a/utilities/automake.mk b/utilities/automake.mk index c4a6d248c274..50c0cfded018 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -71,7 +71,10 @@ utilities/ovn-lib: $(top_builddir)/config.status # ovn-nbctl bin_PROGRAMS += utilities/ovn-nbctl -utilities_ovn_nbctl_SOURCES = utilities/ovn-nbctl.c +utilities_ovn_nbctl_SOURCES = \ + utilities/ovn-dbctl.c \ + utilities/ovn-dbctl.h \ + utilities/ovn-nbctl.c utilities_ovn_nbctl_LDADD = lib/libovn.la $(OVSDB_LIBDIR)/libovsdb.la $(OVS_LIBDIR)/libopenvswitch.la # ovn-sbctl diff --git a/utilities/ovn-dbctl.c b/utilities/ovn-dbctl.c new file mode 100644 index 000000000000..5a41a21ce5c9 --- /dev/null +++ b/utilities/ovn-dbctl.c @@ -0,0 +1,1214 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "ovn-dbctl.h" + +#include + +#include "command-line.h" +#include "daemon.h" +#include "db-ctl-base.h" +#include "fatal-signal.h" +#include "jsonrpc.h" +#include "memory.h" +#include "openvswitch/poll-loop.h" +#include "openvswitch/vlog.h" +#include "ovn-util.h" +#include "ovsdb-idl.h" +#include "process.h" +#include "simap.h" +#include "stream-ssl.h" +#include "svec.h" +#include "table.h" +#include "timer.h" +#include "unixctl.h" +#include "util.h" + +VLOG_DEFINE_THIS_MODULE(ovn_dbctl); + +/* --db: The database server to contact. */ +static const char *db; + +/* --oneline: Write each command's output as a single line? */ +static bool oneline; + +/* --dry-run: Do not commit any changes. */ +static bool dry_run; + +/* --wait=TYPE: Wait for configuration change to take effect? */ +static enum nbctl_wait_type wait_type = NBCTL_WAIT_NONE; + +static bool print_wait_time = false; + +/* --timeout: Time to wait for a connection to 'db'. */ +static unsigned int timeout; + +/* Format for table output. */ +static struct table_style table_style = TABLE_STYLE_DEFAULT; + +/* The IDL we're using and the current transaction, if any. This is for use by + * ovn_dbctl_exit() only, to allow it to clean up. Other code should use its + * context arguments. */ +static struct ovsdb_idl *the_idl; +static struct ovsdb_idl_txn *the_idl_txn; + +/* --leader-only, --no-leader-only: Only accept the leader in a cluster. */ +static int leader_only = true; + +/* --shuffle-remotes, --no-shuffle-remotes: Shuffle the order of remotes that + * are specified in the connetion method string. */ +static int shuffle_remotes = true; + +/* --unixctl-path: Path to use for unixctl server socket, for daemon mode. */ +static char *unixctl_path; + +static unixctl_cb_func server_cmd_exit; +static unixctl_cb_func server_cmd_run; + +static struct option *get_all_options(void); +static bool has_option(const struct ovs_cmdl_parsed_option *, size_t n, + int option); +static void dbctl_client(const struct ovn_dbctl_options *dbctl_options, + const char *socket_name, + const struct ovs_cmdl_parsed_option *, size_t n, + int argc, char *argv[]); +static bool will_detach(const struct ovs_cmdl_parsed_option *, size_t n); +static void apply_options_direct(const struct ovn_dbctl_options *dbctl_options, + const struct ovs_cmdl_parsed_option *, + size_t n, struct shash *local_options); +static char * OVS_WARN_UNUSED_RESULT run_prerequisites( + const struct ovn_dbctl_options *dbctl_options, + struct ctl_command[], size_t n_commands, struct ovsdb_idl *); +static char * OVS_WARN_UNUSED_RESULT do_dbctl( + const struct ovn_dbctl_options *dbctl_options, + const char *args, struct ctl_command *, size_t n, + struct ovsdb_idl *, const struct timer *, bool *retry); +static char * OVS_WARN_UNUSED_RESULT main_loop( + const struct ovn_dbctl_options *, const char *args, + struct ctl_command *commands, size_t n_commands, + struct ovsdb_idl *idl, const struct timer *); +static void server_loop(const struct ovn_dbctl_options *dbctl_options, + struct ovsdb_idl *idl, int argc, char *argv[]); +static void ovn_dbctl_exit(int status); + +int +ovn_dbctl_main(int argc, char *argv[], + const struct ovn_dbctl_options *dbctl_options) +{ + struct ovsdb_idl *idl; + struct shash local_options; + + ovn_set_program_name(argv[0]); + fatal_ignore_sigpipe(); + vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); + vlog_set_levels_from_string_assert("reconnect:warn"); + + ctl_init__(dbctl_options->idl_class, + dbctl_options->tables, + dbctl_options->cmd_show_table, + ovn_dbctl_exit); + ctl_register_commands(dbctl_options->commands); + + /* Check if options are set via env var. */ + char **argv_ = ovs_cmdl_env_parse_all( + &argc, argv, getenv(dbctl_options->options_env_var_name)); + + /* This utility has three operation modes: + * + * - Direct: Executes commands by contacting ovsdb-server directly. + * + * - Server: Runs in the background as a daemon waiting for requests + * from a process running in client mode. + * + * - Client: Executes commands by passing them to a process running in + * the server mode. + * + * At this point we don't know what mode we're running in. The mode partly + * depends on the command line. So, for now we transform the command line + * into a parsed form, and figure out what to do with it later. + */ + struct ovs_cmdl_parsed_option *parsed_options; + size_t n_parsed_options; + char *error_s = ovs_cmdl_parse_all(argc, argv_, get_all_options(), + &parsed_options, &n_parsed_options); + if (error_s) { + ctl_fatal("%s", error_s); + } + + /* Now figure out the operation mode: + * + * - A --detach option implies server mode. + * + * - An OVN_??_DAEMON environment variable implies client mode. + * + * - Otherwise, we're in direct mode. */ + const char *socket_name = (unixctl_path ? unixctl_path + : getenv(dbctl_options->daemon_env_var_name)); + if (((socket_name && socket_name[0]) + || has_option(parsed_options, n_parsed_options, 'u')) + && !will_detach(parsed_options, n_parsed_options)) { + dbctl_client(dbctl_options, socket_name, + parsed_options, n_parsed_options, argc, argv_); + } + + /* Parse command line. */ + shash_init(&local_options); + apply_options_direct(dbctl_options, + parsed_options, n_parsed_options, &local_options); + free(parsed_options); + + bool daemon_mode = false; + if (get_detach()) { + if (argc != optind) { + ctl_fatal("non-option arguments not supported with --detach " + "(use --help for help)"); + } + daemon_mode = true; + } + /* Initialize IDL. */ + idl = the_idl = ovsdb_idl_create_unconnected(dbctl_options->idl_class, + true); + ovsdb_idl_set_shuffle_remotes(idl, shuffle_remotes); + /* "retry" is true iff in daemon mode. */ + ovsdb_idl_set_remote(idl, db, daemon_mode); + ovsdb_idl_set_leader_only(idl, leader_only); + + if (daemon_mode) { + server_loop(dbctl_options, idl, argc, argv_); + } else { + struct ctl_command *commands; + size_t n_commands; + char *error; + + error = ctl_parse_commands(argc - optind, argv_ + optind, + &local_options, &commands, &n_commands); + if (error) { + ctl_fatal("%s", error); + } + + char *args = process_escape_args(argv_); + VLOG(ctl_might_write_to_db(commands, n_commands) ? VLL_INFO : VLL_DBG, + "Called as %s", args); + + ctl_timeout_setup(timeout); + + error = run_prerequisites(dbctl_options, commands, n_commands, idl); + if (error) { + goto cleanup; + } + + error = main_loop(dbctl_options, args, commands, n_commands, idl, NULL); + +cleanup: + free(args); + + struct ctl_command *c; + for (c = commands; c < &commands[n_commands]; c++) { + ds_destroy(&c->output); + table_destroy(c->table); + free(c->table); + shash_destroy_free_data(&c->options); + } + free(commands); + if (error) { + ctl_fatal("%s", error); + } + } + + ovsdb_idl_destroy(idl); + idl = the_idl = NULL; + + for (int i = 0; i < argc; i++) { + free(argv_[i]); + } + free(argv_); + exit(EXIT_SUCCESS); +} + +static char * +main_loop(const struct ovn_dbctl_options *dbctl_options, + const char *args, struct ctl_command *commands, size_t n_commands, + struct ovsdb_idl *idl, const struct timer *wait_timeout) +{ + unsigned int seqno; + bool idl_ready; + + /* Execute the commands. + * + * 'seqno' is the database sequence number for which we last tried to + * execute our transaction. There's no point in trying to commit more than + * once for any given sequence number, because if the transaction fails + * it's because the database changed and we need to obtain an up-to-date + * view of the database before we try the transaction again. */ + seqno = ovsdb_idl_get_seqno(idl); + + /* IDL might have already obtained the database copy during previous + * invocation. If so, we can't expect the sequence number to change before + * we issue any new requests. */ + idl_ready = ovsdb_idl_has_ever_connected(idl); + for (;;) { + ovsdb_idl_run(idl); + if (!ovsdb_idl_is_alive(idl)) { + int retval = ovsdb_idl_get_last_error(idl); + ctl_fatal("%s: database connection failed (%s)", + db, ovs_retval_to_string(retval)); + } + + if (idl_ready || seqno != ovsdb_idl_get_seqno(idl)) { + idl_ready = false; + seqno = ovsdb_idl_get_seqno(idl); + + bool retry; + char *error = do_dbctl(dbctl_options, + args, commands, n_commands, idl, + wait_timeout, &retry); + if (error) { + return error; + } + if (!retry) { + return NULL; + } + } + + if (seqno == ovsdb_idl_get_seqno(idl)) { + ovsdb_idl_wait(idl); + poll_block(); + } + } + + return NULL; +} + +/* All options that affect the main loop and are not external. */ +#define MAIN_LOOP_OPTION_ENUMS \ + OPT_NO_WAIT, \ + OPT_WAIT, \ + OPT_PRINT_WAIT_TIME, \ + OPT_DRY_RUN, \ + OPT_ONELINE + +#define MAIN_LOOP_LONG_OPTIONS \ + {"no-wait", no_argument, NULL, OPT_NO_WAIT}, \ + {"wait", required_argument, NULL, OPT_WAIT}, \ + {"print-wait-time", no_argument, NULL, OPT_PRINT_WAIT_TIME}, \ + {"dry-run", no_argument, NULL, OPT_DRY_RUN}, \ + {"oneline", no_argument, NULL, OPT_ONELINE}, \ + {"timeout", required_argument, NULL, 't'} + +enum { + OPT_DB = UCHAR_MAX + 1, + OPT_NO_SYSLOG, + OPT_LOCAL, + OPT_COMMANDS, + OPT_OPTIONS, + OPT_LEADER_ONLY, + OPT_NO_LEADER_ONLY, + OPT_SHUFFLE_REMOTES, + OPT_NO_SHUFFLE_REMOTES, + OPT_BOOTSTRAP_CA_CERT, + MAIN_LOOP_OPTION_ENUMS, + OVN_DAEMON_OPTION_ENUMS, + VLOG_OPTION_ENUMS, + TABLE_OPTION_ENUMS, + SSL_OPTION_ENUMS, +}; + +static char * OVS_WARN_UNUSED_RESULT +handle_main_loop_option(int opt, const char *arg, bool *handled) +{ + ovs_assert(handled); + *handled = true; + + switch (opt) { + case OPT_ONELINE: + oneline = true; + break; + + case OPT_NO_WAIT: + wait_type = NBCTL_WAIT_NONE; + break; + + case OPT_WAIT: + if (!strcmp(arg, "none")) { + wait_type = NBCTL_WAIT_NONE; + } else if (!strcmp(arg, "sb")) { + wait_type = NBCTL_WAIT_SB; + } else if (!strcmp(arg, "hv")) { + wait_type = NBCTL_WAIT_HV; + } else { + return xstrdup("argument to --wait must be " + "\"none\", \"sb\", or \"hv\""); + } + break; + + case OPT_PRINT_WAIT_TIME: + print_wait_time = true; + break; + + case OPT_DRY_RUN: + dry_run = true; + break; + + case 't': + if (!str_to_uint(arg, 10, &timeout) || !timeout) { + return xasprintf("value %s on -t or --timeout is invalid", arg); + } + break; + + default: + *handled = false; + break; + } + + return NULL; +} + +static char * OVS_WARN_UNUSED_RESULT +build_short_options(const struct option *long_options, bool print_errors) +{ + char *tmp, *short_options; + + tmp = ovs_cmdl_long_options_to_short_options(long_options); + short_options = xasprintf("+%s%s", print_errors ? "" : ":", tmp); + free(tmp); + + return short_options; +} + +static struct option * OVS_WARN_UNUSED_RESULT +append_command_options(const struct option *options, int opt_val) +{ + struct option *o; + size_t n_allocated; + size_t n_existing; + int i; + + for (i = 0; options[i].name; i++) { + ; + } + n_allocated = i + 1; + n_existing = i; + + /* We want to parse both global and command-specific options here, but + * getopt_long() isn't too convenient for the job. We copy our global + * options into a dynamic array, then append all of the command-specific + * options. */ + o = xmemdup(options, n_allocated * sizeof *options); + ctl_add_cmd_options(&o, &n_existing, &n_allocated, opt_val); + + return o; +} + +static struct option * +get_all_options(void) +{ + static const struct option global_long_options[] = { + {"db", required_argument, NULL, OPT_DB}, + {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, + {"help", no_argument, NULL, 'h'}, + {"commands", no_argument, NULL, OPT_COMMANDS}, + {"options", no_argument, NULL, OPT_OPTIONS}, + {"leader-only", no_argument, NULL, OPT_LEADER_ONLY}, + {"no-leader-only", no_argument, NULL, OPT_NO_LEADER_ONLY}, + {"shuffle-remotes", no_argument, NULL, OPT_SHUFFLE_REMOTES}, + {"no-shuffle-remotes", no_argument, NULL, OPT_NO_SHUFFLE_REMOTES}, + {"version", no_argument, NULL, 'V'}, + {"unixctl", required_argument, NULL, 'u'}, + MAIN_LOOP_LONG_OPTIONS, + OVN_DAEMON_LONG_OPTIONS, + VLOG_LONG_OPTIONS, + STREAM_SSL_LONG_OPTIONS, + {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, + TABLE_LONG_OPTIONS, + {NULL, 0, NULL, 0}, + }; + + static struct option *options; + if (!options) { + options = append_command_options(global_long_options, OPT_LOCAL); + } + + return options; +} + +static bool +has_option(const struct ovs_cmdl_parsed_option *parsed_options, size_t n, + int option) +{ + for (const struct ovs_cmdl_parsed_option *po = parsed_options; + po < &parsed_options[n]; po++) { + if (po->o->val == option) { + return true; + } + } + return false; +} + +static bool +will_detach(const struct ovs_cmdl_parsed_option *parsed_options, size_t n) +{ + return has_option(parsed_options, n, OVN_OPT_DETACH); +} + +static char * OVS_WARN_UNUSED_RESULT +add_local_option(const char *name, const char *arg, + struct shash *local_options) +{ + char *full_name = xasprintf("--%s", name); + if (shash_find(local_options, full_name)) { + char *error = xasprintf("'%s' option specified multiple times", + full_name); + free(full_name); + return error; + } + shash_add_nocopy(local_options, full_name, nullable_xstrdup(arg)); + return NULL; +} + +static void +apply_options_direct(const struct ovn_dbctl_options *dbctl_options, + const struct ovs_cmdl_parsed_option *parsed_options, + size_t n, struct shash *local_options) +{ + for (const struct ovs_cmdl_parsed_option *po = parsed_options; + po < &parsed_options[n]; po++) { + bool handled; + char *error = handle_main_loop_option(po->o->val, po->arg, &handled); + if (error) { + ctl_fatal("%s", error); + } + if (handled) { + continue; + } + + optarg = po->arg; + switch (po->o->val) { + case OPT_DB: + db = po->arg; + break; + + case OPT_NO_SYSLOG: + vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); + break; + + case OPT_LOCAL: + error = add_local_option(po->o->name, po->arg, local_options); + if (error) { + ctl_fatal("%s", error); + } + break; + + case 'h': + dbctl_options->usage(); + exit(EXIT_SUCCESS); + + case OPT_COMMANDS: + ctl_print_commands(); + /* fall through */ + + case OPT_OPTIONS: + ctl_print_options(get_all_options()); + /* fall through */ + + case OPT_LEADER_ONLY: + leader_only = true; + break; + + case OPT_NO_LEADER_ONLY: + leader_only = false; + break; + + case OPT_SHUFFLE_REMOTES: + shuffle_remotes = true; + break; + + case OPT_NO_SHUFFLE_REMOTES: + shuffle_remotes = false; + break; + + case 'u': + unixctl_path = optarg; + break; + + case 'V': + ovn_print_version(0, 0); + printf("DB Schema %s\n", dbctl_options->db_version); + exit(EXIT_SUCCESS); + + OVN_DAEMON_OPTION_HANDLERS + VLOG_OPTION_HANDLERS + TABLE_OPTION_HANDLERS(&table_style) + STREAM_SSL_OPTION_HANDLERS + + case OPT_BOOTSTRAP_CA_CERT: + stream_ssl_set_ca_cert_file(po->arg, true); + break; + + case '?': + exit(EXIT_FAILURE); + + default: + abort(); + + case 0: + break; + } + } + + if (!db) { + db = dbctl_options->default_db; + } +} + +static char * +run_prerequisites(const struct ovn_dbctl_options *dbctl_options, + struct ctl_command *commands, size_t n_commands, + struct ovsdb_idl *idl) +{ + dbctl_options->add_base_prerequisites(idl, wait_type); + + for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) { + if (c->syntax->prerequisites) { + struct ctl_context ctx; + + ds_init(&c->output); + c->table = NULL; + + ctl_context_init(&ctx, c, idl, NULL, NULL, NULL); + (c->syntax->prerequisites)(&ctx); + if (ctx.error) { + char *error = xstrdup(ctx.error); + ctl_context_done(&ctx, c); + return error; + } + ctl_context_done(&ctx, c); + + ovs_assert(!c->output.string); + ovs_assert(!c->table); + } + } + + return NULL; +} + +static void +oneline_format(struct ds *lines, struct ds *s) +{ + size_t j; + + ds_chomp(lines, '\n'); + for (j = 0; j < lines->length; j++) { + int ch = lines->string[j]; + switch (ch) { + case '\n': + ds_put_cstr(s, "\\n"); + break; + + case '\\': + ds_put_cstr(s, "\\\\"); + break; + + default: + ds_put_char(s, ch); + } + } + ds_put_char(s, '\n'); +} + +static void +oneline_print(struct ds *lines) +{ + struct ds s = DS_EMPTY_INITIALIZER; + oneline_format(lines, &s); + fputs(ds_cstr(&s), stdout); + ds_destroy(&s); +} + +static char * +do_dbctl(const struct ovn_dbctl_options *dbctl_options, + const char *args, struct ctl_command *commands, size_t n_commands, + struct ovsdb_idl *idl, const struct timer *wait_timeout, bool *retry) +{ + struct ovsdb_idl_txn *txn; + enum ovsdb_idl_txn_status status; + struct ovsdb_symbol_table *symtab; + struct ctl_command *c; + struct shash_node *node; + char *error = NULL; + + ovs_assert(retry); + + txn = the_idl_txn = ovsdb_idl_txn_create(idl); + if (dry_run) { + ovsdb_idl_txn_set_dry_run(txn); + } + + ovsdb_idl_txn_add_comment(txn, "%s: %s", program_name, args); + + dbctl_options->pre_execute(idl, txn, wait_type); + + symtab = ovsdb_symbol_table_create(); + for (c = commands; c < &commands[n_commands]; c++) { + ds_init(&c->output); + c->table = NULL; + } + struct ctl_context *ctx = dbctl_options->ctx_create(); + ctl_context_init(ctx, NULL, idl, txn, symtab, NULL); + for (c = commands; c < &commands[n_commands]; c++) { + ctl_context_init_command(ctx, c); + if (c->syntax->run) { + (c->syntax->run)(ctx); + } + if (ctx->error) { + error = xstrdup(ctx->error); + ctl_context_done(ctx, c); + goto out_error; + } + ctl_context_done_command(ctx, c); + + if (ctx->try_again) { + ctl_context_done(ctx, NULL); + goto try_again; + } + } + ctl_context_done(ctx, NULL); + + SHASH_FOR_EACH (node, &symtab->sh) { + struct ovsdb_symbol *symbol = node->data; + if (!symbol->created) { + error = xasprintf("row id \"%s\" is referenced but never created " + "(e.g. with \"-- --id=%s create ...\")", + node->name, node->name); + goto out_error; + } + if (!symbol->strong_ref) { + if (!symbol->weak_ref) { + VLOG_WARN("row id \"%s\" was created but no reference to it " + "was inserted, so it will not actually appear in " + "the database", node->name); + } else { + VLOG_WARN("row id \"%s\" was created but only a weak " + "reference to it was inserted, so it will not " + "actually appear in the database", node->name); + } + } + } + + long long int start_time = time_wall_msec(); + status = ovsdb_idl_txn_commit_block(txn); + if (status == TXN_UNCHANGED || status == TXN_SUCCESS) { + for (c = commands; c < &commands[n_commands]; c++) { + if (c->syntax->postprocess) { + ctl_context_init(ctx, c, idl, txn, symtab, NULL); + (c->syntax->postprocess)(ctx); + if (ctx->error) { + error = xstrdup(ctx->error); + ctl_context_done(ctx, c); + goto out_error; + } + ctl_context_done(ctx, c); + } + } + } + + switch (status) { + case TXN_UNCOMMITTED: + case TXN_INCOMPLETE: + OVS_NOT_REACHED(); + + case TXN_ABORTED: + /* Should not happen--we never call ovsdb_idl_txn_abort(). */ + error = xstrdup("transaction aborted"); + goto out_error; + + case TXN_UNCHANGED: + case TXN_SUCCESS: + break; + + case TXN_TRY_AGAIN: + goto try_again; + + case TXN_ERROR: + error = xasprintf("transaction error: %s", + ovsdb_idl_txn_get_error(txn)); + goto out_error; + + case TXN_NOT_LOCKED: + /* Should not happen--we never call ovsdb_idl_set_lock(). */ + error = xstrdup("database not locked"); + goto out_error; + + default: + OVS_NOT_REACHED(); + } + + for (c = commands; c < &commands[n_commands]; c++) { + struct ds *ds = &c->output; + + if (c->table) { + table_print(c->table, &table_style); + } else if (oneline) { + oneline_print(ds); + } else { + fputs(ds_cstr(ds), stdout); + } + } + + if (dbctl_options->post_execute) { + error = dbctl_options->post_execute(idl, txn, status, wait_type, + wait_timeout, start_time, + print_wait_time); + if (error) { + goto out_error; + } + } + + dbctl_options->ctx_destroy(ctx); + ovsdb_symbol_table_destroy(symtab); + ovsdb_idl_txn_destroy(txn); + the_idl_txn = NULL; + + *retry = false; + return NULL; + +try_again: + /* Our transaction needs to be rerun, or a prerequisite was not met. Free + * resources and return so that the caller can try again. */ + *retry = true; + +out_error: + ovsdb_idl_txn_abort(txn); + ovsdb_idl_txn_destroy(txn); + the_idl_txn = NULL; + + dbctl_options->ctx_destroy(ctx); + ovsdb_symbol_table_destroy(symtab); + return error; +} + +/* Frees the current transaction and the underlying IDL and then calls + * exit(status). + * + * Freeing the transaction and the IDL is not strictly necessary, but it makes + * for a clean memory leak report from valgrind in the normal case. That makes + * it easier to notice real memory leaks. */ +static void +ovn_dbctl_exit(int status) +{ + if (the_idl_txn) { + ovsdb_idl_txn_abort(the_idl_txn); + ovsdb_idl_txn_destroy(the_idl_txn); + } + ovsdb_idl_destroy(the_idl); + exit(status); +} + +/* Server implementation. */ + +#undef ctl_fatal + +static const struct option * +find_option_by_value(const struct option *options, int value) +{ + const struct option *o; + + for (o = options; o->name; o++) { + if (o->val == value) { + return o; + } + } + return NULL; +} + +static char * OVS_WARN_UNUSED_RESULT +server_parse_options(int argc, char *argv[], struct shash *local_options, + int *n_options_p) +{ + static const struct option global_long_options[] = { + VLOG_LONG_OPTIONS, + MAIN_LOOP_LONG_OPTIONS, + TABLE_LONG_OPTIONS, + {NULL, 0, NULL, 0}, + }; + const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; + char *short_options; + struct option *options; + char *error = NULL; + + ovs_assert(n_options_p); + + short_options = build_short_options(global_long_options, false); + options = append_command_options(global_long_options, OPT_LOCAL); + + optind = 0; + opterr = 0; + for (;;) { + int idx; + int c; + + c = getopt_long(argc, argv, short_options, options, &idx); + if (c == -1) { + break; + } + + bool handled; + error = handle_main_loop_option(c, optarg, &handled); + if (error) { + goto out; + } + if (handled) { + continue; + } + + switch (c) { + case OPT_LOCAL: + error = add_local_option(options[idx].name, optarg, local_options); + if (error) { + goto out; + } + break; + + VLOG_OPTION_HANDLERS + TABLE_OPTION_HANDLERS(&table_style) + + case '?': + if (find_option_by_value(options, optopt)) { + error = xasprintf("option '%s' doesn't allow an argument", + argv[optind-1]); + } else if (optopt) { + error = xasprintf("unrecognized option '%c'", optopt); + } else { + error = xasprintf("unrecognized option '%s'", argv[optind-1]); + } + goto out; + break; + + case ':': + error = xasprintf("option '%s' requires an argument", + argv[optind-1]); + goto out; + break; + + case 0: + break; + + default: + error = xasprintf("unhandled option '%c'", c); + goto out; + break; + } + } + *n_options_p = optind; + +out: + for (int i = n_global_long_options; options[i].name; i++) { + free(CONST_CAST(char *, options[i].name)); + } + free(options); + free(short_options); + + return error; +} + +static void +server_cmd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[] OVS_UNUSED, void *exiting_) +{ + bool *exiting = exiting_; + *exiting = true; + unixctl_command_reply(conn, NULL); +} + +struct server_cmd_run_ctx { + struct ovsdb_idl *idl; + const struct ovn_dbctl_options *dbctl_options; +}; + +static void +server_cmd_run(struct unixctl_conn *conn, int argc, const char **argv_, + void *ctx_) +{ + struct server_cmd_run_ctx *ctx = ctx_; + struct ovsdb_idl *idl = ctx->idl; + const struct ovn_dbctl_options *dbctl_options = ctx->dbctl_options; + + struct ctl_command *commands = NULL; + struct shash local_options; + size_t n_commands = 0; + int n_options = 0; + char *error = NULL; + + /* Copy args so that getopt() can permute them. Leave last entry NULL. */ + char **argv = xcalloc(argc + 1, sizeof *argv); + for (int i = 0; i < argc; i++) { + argv[i] = xstrdup(argv_[i]); + } + + /* Reset global state. */ + oneline = false; + dry_run = false; + wait_type = NBCTL_WAIT_NONE; + timeout = 0; + table_style = table_style_default; + + /* Parse commands & options. */ + char *args = process_escape_args(argv); + shash_init(&local_options); + error = server_parse_options(argc, argv, &local_options, &n_options); + if (error) { + unixctl_command_reply_error(conn, error); + goto out; + } + error = ctl_parse_commands(argc - n_options, argv + n_options, + &local_options, &commands, &n_commands); + if (error) { + unixctl_command_reply_error(conn, error); + goto out; + } + VLOG(ctl_might_write_to_db(commands, n_commands) ? VLL_INFO : VLL_DBG, + "Running command %s", args); + + struct timer *wait_timeout = NULL; + struct timer wait_timeout_; + if (timeout) { + wait_timeout = &wait_timeout_; + timer_set_duration(wait_timeout, timeout * 1000); + } + + error = run_prerequisites(dbctl_options, commands, n_commands, idl); + if (error) { + unixctl_command_reply_error(conn, error); + goto out; + } + error = main_loop(dbctl_options, args, commands, n_commands, idl, wait_timeout); + if (error) { + unixctl_command_reply_error(conn, error); + goto out; + } + + struct ds output = DS_EMPTY_INITIALIZER; + table_format_reset(); + for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) { + if (c->table) { + table_format(c->table, &table_style, &output); + } else if (oneline) { + oneline_format(&c->output, &output); + } else { + ds_put_cstr(&output, ds_cstr_ro(&c->output)); + } + } + unixctl_command_reply(conn, ds_cstr_ro(&output)); + ds_destroy(&output); + +out: + free(error); + + struct ctl_command *c; + for (c = commands; c < &commands[n_commands]; c++) { + ds_destroy(&c->output); + table_destroy(c->table); + free(c->table); + shash_destroy_free_data(&c->options); + } + free(commands); + shash_destroy_free_data(&local_options); + free(args); + for (int i = 0; i < argc; i++) { + free(argv[i]); + } + free(argv); +} + +static void +server_loop(const struct ovn_dbctl_options *dbctl_options, + struct ovsdb_idl *idl, int argc, char *argv[]) +{ + struct unixctl_server *server = NULL; + bool exiting = false; + + service_start(&argc, &argv); + daemonize_start(false); + + char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path); + int error = unixctl_server_create(abs_unixctl_path, &server); + free(abs_unixctl_path); + + if (error) { + ctl_fatal("failed to create unixctl server (%s)", + ovs_retval_to_string(error)); + } + puts(unixctl_server_get_path(server)); + fflush(stdout); + + struct server_cmd_run_ctx server_cmd_run_ctx = { + .idl = idl, + .dbctl_options = dbctl_options + }; + unixctl_command_register("run", "", 0, INT_MAX, server_cmd_run, + &server_cmd_run_ctx); + unixctl_command_register("exit", "", 0, 0, server_cmd_exit, &exiting); + + for (;;) { + memory_run(); + if (memory_should_report()) { + struct simap usage = SIMAP_INITIALIZER(&usage); + + /* Nothing special to report yet. */ + memory_report(&usage); + simap_destroy(&usage); + } + + ovsdb_idl_run(idl); + if (!ovsdb_idl_is_alive(idl)) { + int retval = ovsdb_idl_get_last_error(idl); + ctl_fatal("%s: database connection failed (%s)", + db, ovs_retval_to_string(retval)); + } + + if (ovsdb_idl_has_ever_connected(idl)) { + daemonize_complete(); + } + unixctl_server_run(server); + + if (exiting) { + break; + } + + memory_wait(); + ovsdb_idl_wait(idl); + unixctl_server_wait(server); + poll_block(); + } + + unixctl_server_destroy(server); +} + +static void +dbctl_client(const struct ovn_dbctl_options *dbctl_options, + const char *socket_name, + const struct ovs_cmdl_parsed_option *parsed_options, size_t n, + int argc, char *argv[]) +{ + struct svec args = SVEC_EMPTY_INITIALIZER; + + for (const struct ovs_cmdl_parsed_option *po = parsed_options; + po < &parsed_options[n]; po++) { + optarg = po->arg; + switch (po->o->val) { + case OPT_DB: + VLOG_WARN("not using %s daemon because of %s option", + program_name, po->o->name); + svec_destroy(&args); + return; + + case OPT_NO_SYSLOG: + vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); + break; + + case 'h': + dbctl_options->usage(); + exit(EXIT_SUCCESS); + + case OPT_COMMANDS: + ctl_print_commands(); + /* fall through */ + + case OPT_OPTIONS: + ctl_print_options(get_all_options()); + /* fall through */ + + case OPT_LEADER_ONLY: + case OPT_NO_LEADER_ONLY: + case OPT_SHUFFLE_REMOTES: + case OPT_NO_SHUFFLE_REMOTES: + case OPT_BOOTSTRAP_CA_CERT: + STREAM_SSL_CASES + OVN_DAEMON_OPTION_CASES + VLOG_INFO("using %s daemon, ignoring %s option", + program_name, po->o->name); + break; + + case 'u': + socket_name = optarg; + break; + + case 'V': + ovs_print_version(0, 0); + printf("DB Schema %s\n", dbctl_options->db_version); + exit(EXIT_SUCCESS); + + case 't': + if (!str_to_uint(po->arg, 10, &timeout) || !timeout) { + ctl_fatal("value %s on -t or --timeout is invalid", po->arg); + } + break; + + VLOG_OPTION_HANDLERS + + case OPT_LOCAL: + default: + if (po->arg) { + svec_add_nocopy(&args, + xasprintf("--%s=%s", po->o->name, po->arg)); + } else { + svec_add_nocopy(&args, xasprintf("--%s", po->o->name)); + } + break; + } + } + + ovs_assert(socket_name && socket_name[0]); + + svec_add(&args, "--"); + for (int i = optind; i < argc; i++) { + svec_add(&args, argv[i]); + } + + ctl_timeout_setup(timeout); + + struct jsonrpc *client; + int error = unixctl_client_create(socket_name, &client); + if (error) { + ctl_fatal("%s: could not connect to %s daemon (%s); " + "unset %s to avoid using daemon", + socket_name, program_name, ovs_strerror(error), + dbctl_options->daemon_env_var_name); + } + + char *cmd_result; + char *cmd_error; + error = unixctl_client_transact(client, "run", + args.n, args.names, + &cmd_result, &cmd_error); + if (error) { + ctl_fatal("%s: transaction error (%s)", + socket_name, ovs_strerror(error)); + } + svec_destroy(&args); + + int exit_status; + if (cmd_error) { + exit_status = EXIT_FAILURE; + fprintf(stderr, "%s: %s", program_name, cmd_error); + } else { + exit_status = EXIT_SUCCESS; + fputs(cmd_result, stdout); + } + free(cmd_result); + free(cmd_error); + jsonrpc_close(client); + exit(exit_status); +} diff --git a/utilities/ovn-dbctl.h b/utilities/ovn-dbctl.h new file mode 100644 index 000000000000..5accf3c5e028 --- /dev/null +++ b/utilities/ovn-dbctl.h @@ -0,0 +1,60 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OVN_DBCTL_H +#define OVN_DBCTL_H 1 + +/* ovn-nbctl infrastructure code. */ + +#include +#include "ovsdb-idl.h" + +struct timer; + +enum nbctl_wait_type { + NBCTL_WAIT_NONE, /* Do not wait. */ + NBCTL_WAIT_SB, /* Wait for southbound database updates. */ + NBCTL_WAIT_HV /* Wait for hypervisors to catch up. */ +}; + +struct ovn_dbctl_options { + const char *db_version; /* Database schema version. */ + const char *default_db; /* Default database remote. */ + + /* Names of important environment variables. */ + const char *options_env_var_name; /* OVN_??_OPTIONS. */ + const char *daemon_env_var_name; /* OVN_??_DAEMON. */ + + const struct ovsdb_idl_class *idl_class; + const struct ctl_table_class *tables; + struct cmd_show_table *cmd_show_table; + const struct ctl_command_syntax *commands; + + void (*usage)(void); + + void (*add_base_prerequisites)(struct ovsdb_idl *, enum nbctl_wait_type); + void (*pre_execute)(struct ovsdb_idl *, struct ovsdb_idl_txn *, + enum nbctl_wait_type); + char *(*post_execute)(struct ovsdb_idl *, struct ovsdb_idl_txn *, + enum ovsdb_idl_txn_status, enum nbctl_wait_type, + const struct timer *wait_timeout, + long long int start_time, bool print_wait_time); + + struct ctl_context *(*ctx_create)(void); + void (*ctx_destroy)(struct ctl_context *); +}; + +int ovn_dbctl_main(int argc, char *argv[], const struct ovn_dbctl_options *); + +#endif /* ovn-dbctl.h */ diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 18405835699d..877b39f07e92 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -30,6 +30,7 @@ #include "lib/ovn-nb-idl.h" #include "lib/ovn-util.h" #include "memory.h" +#include "ovn-dbctl.h" #include "packets.h" #include "openvswitch/poll-loop.h" #include "process.h" @@ -48,83 +49,109 @@ VLOG_DEFINE_THIS_MODULE(nbctl); -/* --db: The database server to contact. */ -static const char *db; +/* Should we wait (if specified by 'wait_type') even if the commands don't + * change the database at all? */ +static bool force_wait = false; -/* --oneline: Write each command's output as a single line? */ -static bool oneline; +static void +nbctl_add_base_prerequisites(struct ovsdb_idl *idl, + enum nbctl_wait_type wait_type) +{ + force_wait = false; -/* --dry-run: Do not commit any changes. */ -static bool dry_run; + ovsdb_idl_add_table(idl, &nbrec_table_nb_global); + if (wait_type == NBCTL_WAIT_SB) { + ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg); + ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg_timestamp); + } else if (wait_type == NBCTL_WAIT_HV) { + ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg); + ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg_timestamp); + } +} -/* --wait=TYPE: Wait for configuration change to take effect? */ -enum nbctl_wait_type { - NBCTL_WAIT_NONE, /* Do not wait. */ - NBCTL_WAIT_SB, /* Wait for southbound database updates. */ - NBCTL_WAIT_HV /* Wait for hypervisors to catch up. */ -}; -static enum nbctl_wait_type wait_type = NBCTL_WAIT_NONE; +static void +nbctl_pre_execute(struct ovsdb_idl *idl, struct ovsdb_idl_txn *txn, + enum nbctl_wait_type wait_type) +{ + const struct nbrec_nb_global *nb = nbrec_nb_global_first(idl); + if (!nb) { + /* XXX add verification that table is empty */ + nb = nbrec_nb_global_insert(txn); + } -static bool print_wait_time = false; + /* Deal with potential overflows. */ + if (nb->nb_cfg == LLONG_MAX) { + nbrec_nb_global_set_nb_cfg(nb, 0); + } -/* Should we wait (if specified by 'wait_type') even if the commands don't - * change the database at all? */ -static bool force_wait = false; + if (wait_type != NBCTL_WAIT_NONE) { + ovsdb_idl_txn_increment(txn, &nb->header_, &nbrec_nb_global_col_nb_cfg, + force_wait); + } +} + +static char * +nbctl_post_execute(struct ovsdb_idl *idl, struct ovsdb_idl_txn *txn, + enum ovsdb_idl_txn_status status, + enum nbctl_wait_type wait_type, + const struct timer *wait_timeout, long long int start_time, + bool print_wait_time) +{ + if (wait_type == NBCTL_WAIT_NONE) { + if (force_wait) { + VLOG_INFO("\"sync\" command has no effect without --wait"); + } + return NULL; + } + if (status == TXN_UNCHANGED) { + return NULL; + } + + ovs_assert(status == TXN_SUCCESS); + int64_t next_cfg = ovsdb_idl_txn_get_increment_new_value(txn); + ovsdb_idl_enable_reconnect(idl); + for (;;) { + ovsdb_idl_run(idl); + + const struct nbrec_nb_global *nb; + NBREC_NB_GLOBAL_FOR_EACH (nb, idl) { + int64_t cur_cfg = (wait_type == NBCTL_WAIT_SB + ? nb->sb_cfg + : MIN(nb->sb_cfg, nb->hv_cfg)); + if (cur_cfg >= next_cfg) { + if (print_wait_time) { + printf("Time spent on processing nb_cfg %"PRId64":\n", + next_cfg); + + long long int nb_timestamp = nb->nb_cfg_timestamp; + long long int sb_timestamp = nb->sb_cfg_timestamp; + long long int hv_timestamp = nb->hv_cfg_timestamp; + printf("\tovn-northd delay before processing:" + "\t%lldms\n", nb_timestamp - start_time); + printf("\tovn-northd completion:" + "\t\t\t%lldms\n", sb_timestamp - start_time); + if (wait_type == NBCTL_WAIT_HV) { + printf("\tovn-controller(s) completion:" + "\t\t%lldms\n", hv_timestamp - start_time); + } + } + return NULL; + } + } + ovsdb_idl_wait(idl); + if (wait_timeout) { + timer_wait(wait_timeout); + } + poll_block(); + if (wait_timeout && timer_expired(wait_timeout)) { + return xstrdup("timeout expired"); + } + } +} -/* --timeout: Time to wait for a connection to 'db'. */ -static unsigned int timeout; - -/* Format for table output. */ -static struct table_style table_style = TABLE_STYLE_DEFAULT; - -/* The IDL we're using and the current transaction, if any. - * This is for use by nbctl_exit() only, to allow it to clean up. - * Other code should use its context arguments. */ -static struct ovsdb_idl *the_idl; -static struct ovsdb_idl_txn *the_idl_txn; -OVS_NO_RETURN static void nbctl_exit(int status); - -/* --leader-only, --no-leader-only: Only accept the leader in a cluster. */ -static int leader_only = true; - -/* --shuffle-remotes, --no-shuffle-remotes: Shuffle the order of remotes that - * are specified in the connetion method string. */ -static int shuffle_remotes = true; - -/* --unixctl-path: Path to use for unixctl server socket, for daemon mode. */ -static char *unixctl_path; - -static unixctl_cb_func server_cmd_exit; -static unixctl_cb_func server_cmd_run; - -static void nbctl_cmd_init(void); -OVS_NO_RETURN static void usage(void); -static struct option *get_all_options(void); -static bool has_option(const struct ovs_cmdl_parsed_option *, size_t n, - int option); -static void nbctl_client(const char *socket_name, - const struct ovs_cmdl_parsed_option *, size_t n, - int argc, char *argv[]); -static bool will_detach(const struct ovs_cmdl_parsed_option *, size_t n); -static void apply_options_direct(const struct ovs_cmdl_parsed_option *, - size_t n, struct shash *local_options); -static char * OVS_WARN_UNUSED_RESULT run_prerequisites(struct ctl_command[], - size_t n_commands, - struct ovsdb_idl *); -static char * OVS_WARN_UNUSED_RESULT do_nbctl(const char *args, - struct ctl_command *, size_t n, - struct ovsdb_idl *, - const struct timer *, - bool *retry); static char * OVS_WARN_UNUSED_RESULT dhcp_options_get( struct ctl_context *ctx, const char *id, bool must_exist, const struct nbrec_dhcp_options **); -static char * OVS_WARN_UNUSED_RESULT main_loop(const char *args, - struct ctl_command *commands, - size_t n_commands, - struct ovsdb_idl *idl, - const struct timer *); -static void server_loop(struct ovsdb_idl *idl, int argc, char *argv[]); /* A context for keeping track of which switch/router certain ports are * connected to. @@ -134,35 +161,41 @@ static void server_loop(struct ovsdb_idl *idl, int argc, char *argv[]); * until transaction is committed and updates received from the server. */ struct nbctl_context { struct ctl_context base; + + bool context_valid; struct shash lsp_to_ls_map; struct shash lrp_to_lr_map; - bool context_valid; }; -static void -nbctl_context_init(struct nbctl_context *nbctx) +static struct ctl_context * +nbctl_ctx_create(void) { - nbctx->context_valid = false; - shash_init(&nbctx->lsp_to_ls_map); - shash_init(&nbctx->lrp_to_lr_map); + struct nbctl_context *nbctx = xmalloc(sizeof *nbctx); + *nbctx = (struct nbctl_context) { + .context_valid = false, + .lsp_to_ls_map = SHASH_INITIALIZER(&nbctx->lsp_to_ls_map), + .lrp_to_lr_map = SHASH_INITIALIZER(&nbctx->lrp_to_lr_map), + }; + return &nbctx->base; } static void -nbctl_context_destroy(struct nbctl_context *nbctx) +nbctl_ctx_destroy(struct ctl_context *base) { + struct nbctl_context *nbctx + = CONTAINER_OF(base, struct nbctl_context, base); nbctx->context_valid = false; shash_destroy(&nbctx->lsp_to_ls_map); shash_destroy(&nbctx->lrp_to_lr_map); + free(nbctx); } /* Casts 'base' into 'struct nbctl_context' and initializes it if needed. */ static struct nbctl_context * nbctl_context_get(struct ctl_context *base) { - struct nbctl_context *nbctx; - - nbctx = CONTAINER_OF(base, struct nbctl_context, base); - + struct nbctl_context *nbctx + = CONTAINER_OF(base, struct nbctl_context, base); if (nbctx->context_valid) { return nbctx; } @@ -185,466 +218,8 @@ nbctl_context_get(struct ctl_context *base) return nbctx; } -int -main(int argc, char *argv[]) -{ - struct ovsdb_idl *idl; - struct shash local_options; - - ovn_set_program_name(argv[0]); - fatal_ignore_sigpipe(); - vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); - vlog_set_levels_from_string_assert("reconnect:warn"); - - nbctl_cmd_init(); - - /* Check if options are set via env var. */ - char **argv_ = ovs_cmdl_env_parse_all(&argc, argv, - getenv("OVN_NBCTL_OPTIONS")); - - /* ovn-nbctl has three operation modes: - * - * - Direct: Executes commands by contacting ovsdb-server directly. - * - * - Server: Runs in the background as a daemon waiting for requests - * from ovn-nbctl running in client mode. - * - * - Client: Executes commands by passing them to an ovn-nbctl running - * in the server mode. - * - * At this point we don't know what mode we're running in. The mode partly - * depends on the command line. So, for now we transform the command line - * into a parsed form, and figure out what to do with it later. - */ - struct ovs_cmdl_parsed_option *parsed_options; - size_t n_parsed_options; - char *error_s = ovs_cmdl_parse_all(argc, argv_, get_all_options(), - &parsed_options, &n_parsed_options); - if (error_s) { - ctl_fatal("%s", error_s); - } - - /* Now figure out the operation mode: - * - * - A --detach option implies server mode. - * - * - An OVN_NB_DAEMON environment variable implies client mode. - * - * - Otherwise, we're in direct mode. */ - char *socket_name = unixctl_path ?: getenv("OVN_NB_DAEMON"); - if (((socket_name && socket_name[0]) - || has_option(parsed_options, n_parsed_options, 'u')) - && !will_detach(parsed_options, n_parsed_options)) { - nbctl_client(socket_name, parsed_options, n_parsed_options, - argc, argv_); - } - - /* Parse command line. */ - shash_init(&local_options); - apply_options_direct(parsed_options, n_parsed_options, &local_options); - free(parsed_options); - - bool daemon_mode = false; - if (get_detach()) { - if (argc != optind) { - ctl_fatal("non-option arguments not supported with --detach " - "(use --help for help)"); - } - daemon_mode = true; - } - /* Initialize IDL. */ - idl = the_idl = ovsdb_idl_create_unconnected(&nbrec_idl_class, true); - ovsdb_idl_set_shuffle_remotes(idl, shuffle_remotes); - /* "retry" is true iff in daemon mode. */ - ovsdb_idl_set_remote(idl, db, daemon_mode); - ovsdb_idl_set_leader_only(idl, leader_only); - - if (daemon_mode) { - server_loop(idl, argc, argv_); - } else { - struct ctl_command *commands; - size_t n_commands; - char *error; - - error = ctl_parse_commands(argc - optind, argv_ + optind, - &local_options, &commands, &n_commands); - if (error) { - ctl_fatal("%s", error); - } - - char *args = process_escape_args(argv_); - VLOG(ctl_might_write_to_db(commands, n_commands) ? VLL_INFO : VLL_DBG, - "Called as %s", args); - - ctl_timeout_setup(timeout); - - error = run_prerequisites(commands, n_commands, idl); - if (error) { - goto cleanup; - } - - error = main_loop(args, commands, n_commands, idl, NULL); - -cleanup: - free(args); - - struct ctl_command *c; - for (c = commands; c < &commands[n_commands]; c++) { - ds_destroy(&c->output); - table_destroy(c->table); - free(c->table); - shash_destroy_free_data(&c->options); - } - free(commands); - if (error) { - ctl_fatal("%s", error); - } - } - - ovsdb_idl_destroy(idl); - idl = the_idl = NULL; - - for (int i = 0; i < argc; i++) { - free(argv_[i]); - } - free(argv_); - exit(EXIT_SUCCESS); -} - -static char * -main_loop(const char *args, struct ctl_command *commands, size_t n_commands, - struct ovsdb_idl *idl, const struct timer *wait_timeout) -{ - unsigned int seqno; - bool idl_ready; - - /* Execute the commands. - * - * 'seqno' is the database sequence number for which we last tried to - * execute our transaction. There's no point in trying to commit more than - * once for any given sequence number, because if the transaction fails - * it's because the database changed and we need to obtain an up-to-date - * view of the database before we try the transaction again. */ - seqno = ovsdb_idl_get_seqno(idl); - - /* IDL might have already obtained the database copy during previous - * invocation. If so, we can't expect the sequence number to change before - * we issue any new requests. */ - idl_ready = ovsdb_idl_has_ever_connected(idl); - for (;;) { - ovsdb_idl_run(idl); - if (!ovsdb_idl_is_alive(idl)) { - int retval = ovsdb_idl_get_last_error(idl); - ctl_fatal("%s: database connection failed (%s)", - db, ovs_retval_to_string(retval)); - } - - if (idl_ready || seqno != ovsdb_idl_get_seqno(idl)) { - idl_ready = false; - seqno = ovsdb_idl_get_seqno(idl); - - bool retry; - char *error = do_nbctl(args, commands, n_commands, idl, - wait_timeout, &retry); - if (error) { - return error; - } - if (!retry) { - return NULL; - } - } - - if (seqno == ovsdb_idl_get_seqno(idl)) { - ovsdb_idl_wait(idl); - poll_block(); - } - } - - return NULL; -} - -/* All options that affect the main loop and are not external. */ -#define MAIN_LOOP_OPTION_ENUMS \ - OPT_NO_WAIT, \ - OPT_WAIT, \ - OPT_PRINT_WAIT_TIME, \ - OPT_DRY_RUN, \ - OPT_ONELINE - -#define MAIN_LOOP_LONG_OPTIONS \ - {"no-wait", no_argument, NULL, OPT_NO_WAIT}, \ - {"wait", required_argument, NULL, OPT_WAIT}, \ - {"print-wait-time", no_argument, NULL, OPT_PRINT_WAIT_TIME}, \ - {"dry-run", no_argument, NULL, OPT_DRY_RUN}, \ - {"oneline", no_argument, NULL, OPT_ONELINE}, \ - {"timeout", required_argument, NULL, 't'} - -enum { - OPT_DB = UCHAR_MAX + 1, - OPT_NO_SYSLOG, - OPT_LOCAL, - OPT_COMMANDS, - OPT_OPTIONS, - OPT_LEADER_ONLY, - OPT_NO_LEADER_ONLY, - OPT_SHUFFLE_REMOTES, - OPT_NO_SHUFFLE_REMOTES, - OPT_BOOTSTRAP_CA_CERT, - MAIN_LOOP_OPTION_ENUMS, - OVN_DAEMON_OPTION_ENUMS, - VLOG_OPTION_ENUMS, - TABLE_OPTION_ENUMS, - SSL_OPTION_ENUMS, -}; - -static char * OVS_WARN_UNUSED_RESULT -handle_main_loop_option(int opt, const char *arg, bool *handled) -{ - ovs_assert(handled); - *handled = true; - - switch (opt) { - case OPT_ONELINE: - oneline = true; - break; - - case OPT_NO_WAIT: - wait_type = NBCTL_WAIT_NONE; - break; - - case OPT_WAIT: - if (!strcmp(arg, "none")) { - wait_type = NBCTL_WAIT_NONE; - } else if (!strcmp(arg, "sb")) { - wait_type = NBCTL_WAIT_SB; - } else if (!strcmp(arg, "hv")) { - wait_type = NBCTL_WAIT_HV; - } else { - return xstrdup("argument to --wait must be " - "\"none\", \"sb\", or \"hv\""); - } - break; - - case OPT_PRINT_WAIT_TIME: - print_wait_time = true; - break; - - case OPT_DRY_RUN: - dry_run = true; - break; - - case 't': - if (!str_to_uint(arg, 10, &timeout) || !timeout) { - return xasprintf("value %s on -t or --timeout is invalid", arg); - } - break; - - default: - *handled = false; - break; - } - - return NULL; -} - -static char * OVS_WARN_UNUSED_RESULT -build_short_options(const struct option *long_options, bool print_errors) -{ - char *tmp, *short_options; - - tmp = ovs_cmdl_long_options_to_short_options(long_options); - short_options = xasprintf("+%s%s", print_errors ? "" : ":", tmp); - free(tmp); - - return short_options; -} - -static struct option * OVS_WARN_UNUSED_RESULT -append_command_options(const struct option *options, int opt_val) -{ - struct option *o; - size_t n_allocated; - size_t n_existing; - int i; - - for (i = 0; options[i].name; i++) { - ; - } - n_allocated = i + 1; - n_existing = i; - - /* We want to parse both global and command-specific options here, but - * getopt_long() isn't too convenient for the job. We copy our global - * options into a dynamic array, then append all of the command-specific - * options. */ - o = xmemdup(options, n_allocated * sizeof *options); - ctl_add_cmd_options(&o, &n_existing, &n_allocated, opt_val); - - return o; -} - -static struct option * -get_all_options(void) -{ - static const struct option global_long_options[] = { - {"db", required_argument, NULL, OPT_DB}, - {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, - {"help", no_argument, NULL, 'h'}, - {"commands", no_argument, NULL, OPT_COMMANDS}, - {"options", no_argument, NULL, OPT_OPTIONS}, - {"leader-only", no_argument, NULL, OPT_LEADER_ONLY}, - {"no-leader-only", no_argument, NULL, OPT_NO_LEADER_ONLY}, - {"shuffle-remotes", no_argument, NULL, OPT_SHUFFLE_REMOTES}, - {"no-shuffle-remotes", no_argument, NULL, OPT_NO_SHUFFLE_REMOTES}, - {"version", no_argument, NULL, 'V'}, - {"unixctl", required_argument, NULL, 'u'}, - MAIN_LOOP_LONG_OPTIONS, - OVN_DAEMON_LONG_OPTIONS, - VLOG_LONG_OPTIONS, - STREAM_SSL_LONG_OPTIONS, - {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, - TABLE_LONG_OPTIONS, - {NULL, 0, NULL, 0}, - }; - - static struct option *options; - if (!options) { - options = append_command_options(global_long_options, OPT_LOCAL); - } - - return options; -} - -static bool -has_option(const struct ovs_cmdl_parsed_option *parsed_options, size_t n, - int option) -{ - for (const struct ovs_cmdl_parsed_option *po = parsed_options; - po < &parsed_options[n]; po++) { - if (po->o->val == option) { - return true; - } - } - return false; -} - -static bool -will_detach(const struct ovs_cmdl_parsed_option *parsed_options, size_t n) -{ - return has_option(parsed_options, n, OVN_OPT_DETACH); -} - -static char * OVS_WARN_UNUSED_RESULT -add_local_option(const char *name, const char *arg, - struct shash *local_options) -{ - char *full_name = xasprintf("--%s", name); - if (shash_find(local_options, full_name)) { - char *error = xasprintf("'%s' option specified multiple times", - full_name); - free(full_name); - return error; - } - shash_add_nocopy(local_options, full_name, nullable_xstrdup(arg)); - return NULL; -} - static void -apply_options_direct(const struct ovs_cmdl_parsed_option *parsed_options, - size_t n, struct shash *local_options) -{ - for (const struct ovs_cmdl_parsed_option *po = parsed_options; - po < &parsed_options[n]; po++) { - bool handled; - char *error = handle_main_loop_option(po->o->val, po->arg, &handled); - if (error) { - ctl_fatal("%s", error); - } - if (handled) { - continue; - } - - optarg = po->arg; - switch (po->o->val) { - case OPT_DB: - db = po->arg; - break; - - case OPT_NO_SYSLOG: - vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); - break; - - case OPT_LOCAL: - error = add_local_option(po->o->name, po->arg, local_options); - if (error) { - ctl_fatal("%s", error); - } - break; - - case 'h': - usage(); - exit(EXIT_SUCCESS); - - case OPT_COMMANDS: - ctl_print_commands(); - /* fall through */ - - case OPT_OPTIONS: - ctl_print_options(get_all_options()); - /* fall through */ - - case OPT_LEADER_ONLY: - leader_only = true; - break; - - case OPT_NO_LEADER_ONLY: - leader_only = false; - break; - - case OPT_SHUFFLE_REMOTES: - shuffle_remotes = true; - break; - - case OPT_NO_SHUFFLE_REMOTES: - shuffle_remotes = false; - break; - - case 'u': - unixctl_path = optarg; - break; - - case 'V': - ovn_print_version(0, 0); - printf("DB Schema %s\n", nbrec_get_db_version()); - exit(EXIT_SUCCESS); - - OVN_DAEMON_OPTION_HANDLERS - VLOG_OPTION_HANDLERS - TABLE_OPTION_HANDLERS(&table_style) - STREAM_SSL_OPTION_HANDLERS - - case OPT_BOOTSTRAP_CA_CERT: - stream_ssl_set_ca_cert_file(po->arg, true); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - - case 0: - break; - } - } - - if (!db) { - db = default_nb_db(); - } -} - -static void -usage(void) +nbctl_usage(void) { printf("\ %s: OVN northbound DB management utility\n\ @@ -1212,13 +787,9 @@ nbctl_init(struct ctl_context *ctx OVS_UNUSED) } static void -nbctl_pre_sync(struct ctl_context *ctx OVS_UNUSED) +nbctl_pre_sync(struct ctl_context *base OVS_UNUSED) { - if (wait_type != NBCTL_WAIT_NONE) { - force_wait = true; - } else { - VLOG_INFO("\"sync\" command has no effect without --wait"); - } + force_wait = true; } static void @@ -6204,305 +5775,6 @@ static const struct ctl_table_class tables[NBREC_N_TABLES] = { = {&nbrec_connection_col_target, NULL, NULL}, }; -static char * -run_prerequisites(struct ctl_command *commands, size_t n_commands, - struct ovsdb_idl *idl) -{ - ovsdb_idl_add_table(idl, &nbrec_table_nb_global); - if (wait_type == NBCTL_WAIT_SB) { - ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg); - ovsdb_idl_add_column(idl, &nbrec_nb_global_col_sb_cfg_timestamp); - } else if (wait_type == NBCTL_WAIT_HV) { - ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg); - ovsdb_idl_add_column(idl, &nbrec_nb_global_col_hv_cfg_timestamp); - } - - for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) { - if (c->syntax->prerequisites) { - struct ctl_context ctx; - - ds_init(&c->output); - c->table = NULL; - - ctl_context_init(&ctx, c, idl, NULL, NULL, NULL); - (c->syntax->prerequisites)(&ctx); - if (ctx.error) { - char *error = xstrdup(ctx.error); - ctl_context_done(&ctx, c); - return error; - } - ctl_context_done(&ctx, c); - - ovs_assert(!c->output.string); - ovs_assert(!c->table); - } - } - - return NULL; -} - -static void -oneline_format(struct ds *lines, struct ds *s) -{ - size_t j; - - ds_chomp(lines, '\n'); - for (j = 0; j < lines->length; j++) { - int ch = lines->string[j]; - switch (ch) { - case '\n': - ds_put_cstr(s, "\\n"); - break; - - case '\\': - ds_put_cstr(s, "\\\\"); - break; - - default: - ds_put_char(s, ch); - } - } - ds_put_char(s, '\n'); -} - -static void -oneline_print(struct ds *lines) -{ - struct ds s = DS_EMPTY_INITIALIZER; - oneline_format(lines, &s); - fputs(ds_cstr(&s), stdout); - ds_destroy(&s); -} - -static char * -do_nbctl(const char *args, struct ctl_command *commands, size_t n_commands, - struct ovsdb_idl *idl, const struct timer *wait_timeout, bool *retry) -{ - struct ovsdb_idl_txn *txn; - enum ovsdb_idl_txn_status status; - struct ovsdb_symbol_table *symtab; - struct nbctl_context ctx; - struct ctl_command *c; - struct shash_node *node; - int64_t next_cfg = 0; - char *error = NULL; - int64_t start_time = 0; - - ovs_assert(retry); - - txn = the_idl_txn = ovsdb_idl_txn_create(idl); - if (dry_run) { - ovsdb_idl_txn_set_dry_run(txn); - } - - ovsdb_idl_txn_add_comment(txn, "ovs-nbctl: %s", args); - - const struct nbrec_nb_global *nb = nbrec_nb_global_first(idl); - if (!nb) { - /* XXX add verification that table is empty */ - nb = nbrec_nb_global_insert(txn); - } - - /* Deal with potential overflows. */ - if (nb->nb_cfg == LLONG_MAX) { - nbrec_nb_global_set_nb_cfg(nb, 0); - } - - if (wait_type != NBCTL_WAIT_NONE) { - ovsdb_idl_txn_increment(txn, &nb->header_, &nbrec_nb_global_col_nb_cfg, - force_wait); - } - - symtab = ovsdb_symbol_table_create(); - for (c = commands; c < &commands[n_commands]; c++) { - ds_init(&c->output); - c->table = NULL; - } - nbctl_context_init(&ctx); - ctl_context_init(&ctx.base, NULL, idl, txn, symtab, NULL); - for (c = commands; c < &commands[n_commands]; c++) { - ctl_context_init_command(&ctx.base, c); - if (c->syntax->run) { - (c->syntax->run)(&ctx.base); - } - if (ctx.base.error) { - error = xstrdup(ctx.base.error); - ctl_context_done(&ctx.base, c); - goto out_error; - } - ctl_context_done_command(&ctx.base, c); - - if (ctx.base.try_again) { - ctl_context_done(&ctx.base, NULL); - goto try_again; - } - } - ctl_context_done(&ctx.base, NULL); - - SHASH_FOR_EACH (node, &symtab->sh) { - struct ovsdb_symbol *symbol = node->data; - if (!symbol->created) { - error = xasprintf("row id \"%s\" is referenced but never created " - "(e.g. with \"-- --id=%s create ...\")", - node->name, node->name); - goto out_error; - } - if (!symbol->strong_ref) { - if (!symbol->weak_ref) { - VLOG_WARN("row id \"%s\" was created but no reference to it " - "was inserted, so it will not actually appear in " - "the database", node->name); - } else { - VLOG_WARN("row id \"%s\" was created but only a weak " - "reference to it was inserted, so it will not " - "actually appear in the database", node->name); - } - } - } - - start_time = time_wall_msec(); - status = ovsdb_idl_txn_commit_block(txn); - if (wait_type != NBCTL_WAIT_NONE && status == TXN_SUCCESS) { - next_cfg = ovsdb_idl_txn_get_increment_new_value(txn); - } - if (status == TXN_UNCHANGED || status == TXN_SUCCESS) { - for (c = commands; c < &commands[n_commands]; c++) { - if (c->syntax->postprocess) { - ctl_context_init(&ctx.base, c, idl, txn, symtab, NULL); - (c->syntax->postprocess)(&ctx.base); - if (ctx.base.error) { - error = xstrdup(ctx.base.error); - ctl_context_done(&ctx.base, c); - goto out_error; - } - ctl_context_done(&ctx.base, c); - } - } - } - - switch (status) { - case TXN_UNCOMMITTED: - case TXN_INCOMPLETE: - OVS_NOT_REACHED(); - - case TXN_ABORTED: - /* Should not happen--we never call ovsdb_idl_txn_abort(). */ - error = xstrdup("transaction aborted"); - goto out_error; - - case TXN_UNCHANGED: - case TXN_SUCCESS: - break; - - case TXN_TRY_AGAIN: - goto try_again; - - case TXN_ERROR: - error = xasprintf("transaction error: %s", - ovsdb_idl_txn_get_error(txn)); - goto out_error; - - case TXN_NOT_LOCKED: - /* Should not happen--we never call ovsdb_idl_set_lock(). */ - error = xstrdup("database not locked"); - goto out_error; - - default: - OVS_NOT_REACHED(); - } - - for (c = commands; c < &commands[n_commands]; c++) { - struct ds *ds = &c->output; - - if (c->table) { - table_print(c->table, &table_style); - } else if (oneline) { - oneline_print(ds); - } else { - fputs(ds_cstr(ds), stdout); - } - } - - if (wait_type != NBCTL_WAIT_NONE && status != TXN_UNCHANGED) { - ovsdb_idl_enable_reconnect(idl); - for (;;) { - ovsdb_idl_run(idl); - NBREC_NB_GLOBAL_FOR_EACH (nb, idl) { - int64_t cur_cfg = (wait_type == NBCTL_WAIT_SB - ? nb->sb_cfg - : MIN(nb->sb_cfg, nb->hv_cfg)); - if (cur_cfg >= next_cfg) { - if (print_wait_time) { - printf("Time spent on processing nb_cfg %"PRId64":\n", - next_cfg); - printf("\tovn-northd delay before processing:" - "\t%"PRId64"ms\n", - nb->nb_cfg_timestamp - start_time); - printf("\tovn-northd completion:" - "\t\t\t%"PRId64"ms\n", - nb->sb_cfg_timestamp - start_time); - if (wait_type == NBCTL_WAIT_HV) { - printf("\tovn-controller(s) completion:" - "\t\t%"PRId64"ms\n", - nb->hv_cfg_timestamp - start_time); - } - } - goto done; - } - } - ovsdb_idl_wait(idl); - if (wait_timeout) { - timer_wait(wait_timeout); - } - poll_block(); - if (wait_timeout && timer_expired(wait_timeout)) { - error = xstrdup("timeout expired"); - goto out_error; - } - } - done: ; - } - - nbctl_context_destroy(&ctx); - ovsdb_symbol_table_destroy(symtab); - ovsdb_idl_txn_destroy(txn); - the_idl_txn = NULL; - - *retry = false; - return NULL; - -try_again: - /* Our transaction needs to be rerun, or a prerequisite was not met. Free - * resources and return so that the caller can try again. */ - *retry = true; - -out_error: - ovsdb_idl_txn_abort(txn); - ovsdb_idl_txn_destroy(txn); - the_idl_txn = NULL; - - nbctl_context_destroy(&ctx); - ovsdb_symbol_table_destroy(symtab); - return error; -} - -/* Frees the current transaction and the underlying IDL and then calls - * exit(status). - * - * Freeing the transaction and the IDL is not strictly necessary, but it makes - * for a clean memory leak report from valgrind in the normal case. That makes - * it easier to notice real memory leaks. */ -static void -nbctl_exit(int status) -{ - if (the_idl_txn) { - ovsdb_idl_txn_abort(the_idl_txn); - ovsdb_idl_txn_destroy(the_idl_txn); - } - ovsdb_idl_destroy(the_idl); - exit(status); -} - static const struct ctl_command_syntax nbctl_commands[] = { { "init", 0, 0, "", NULL, nbctl_init, NULL, "", RW }, { "sync", 0, 0, "", nbctl_pre_sync, nbctl_sync, NULL, "", RO }, @@ -6704,397 +5976,30 @@ static const struct ctl_command_syntax nbctl_commands[] = { {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO}, }; -/* Registers nbctl and common db commands. */ -static void -nbctl_cmd_init(void) +int +main(int argc, char *argv[]) { - ctl_init(&nbrec_idl_class, nbrec_table_classes, tables, NULL, nbctl_exit); - ctl_register_commands(nbctl_commands); -} - -/* Server implementation. */ + struct ovn_dbctl_options dbctl_options = { + .db_version = nbrec_get_db_version(), + .default_db = default_nb_db(), -#undef ctl_fatal + .options_env_var_name = "OVN_NBCTL_OPTIONS", + .daemon_env_var_name = "OVN_NB_DAEMON", -static const struct option * -find_option_by_value(const struct option *options, int value) -{ - const struct option *o; + .idl_class = &nbrec_idl_class, + .tables = tables, + .cmd_show_table = NULL, + .commands = nbctl_commands, - for (o = options; o->name; o++) { - if (o->val == value) { - return o; - } - } - return NULL; -} + .usage = nbctl_usage, + .add_base_prerequisites = nbctl_add_base_prerequisites, + .pre_execute = nbctl_pre_execute, + .post_execute = nbctl_post_execute, -static char * OVS_WARN_UNUSED_RESULT -server_parse_options(int argc, char *argv[], struct shash *local_options, - int *n_options_p) -{ - static const struct option global_long_options[] = { - VLOG_LONG_OPTIONS, - MAIN_LOOP_LONG_OPTIONS, - TABLE_LONG_OPTIONS, - {NULL, 0, NULL, 0}, + .ctx_create = nbctl_ctx_create, + .ctx_destroy = nbctl_ctx_destroy, }; - const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; - char *short_options; - struct option *options; - char *error = NULL; - - ovs_assert(n_options_p); - - short_options = build_short_options(global_long_options, false); - options = append_command_options(global_long_options, OPT_LOCAL); - - optind = 0; - opterr = 0; - for (;;) { - int idx; - int c; - - c = getopt_long(argc, argv, short_options, options, &idx); - if (c == -1) { - break; - } - - bool handled; - error = handle_main_loop_option(c, optarg, &handled); - if (error) { - goto out; - } - if (handled) { - continue; - } - - switch (c) { - case OPT_LOCAL: - error = add_local_option(options[idx].name, optarg, local_options); - if (error) { - goto out; - } - break; - - VLOG_OPTION_HANDLERS - TABLE_OPTION_HANDLERS(&table_style) - case '?': - if (find_option_by_value(options, optopt)) { - error = xasprintf("option '%s' doesn't allow an argument", - argv[optind-1]); - } else if (optopt) { - error = xasprintf("unrecognized option '%c'", optopt); - } else { - error = xasprintf("unrecognized option '%s'", argv[optind-1]); - } - goto out; - break; - - case ':': - error = xasprintf("option '%s' requires an argument", - argv[optind-1]); - goto out; - break; - - case 0: - break; - - default: - error = xasprintf("unhandled option '%c'", c); - goto out; - break; - } - } - *n_options_p = optind; - -out: - for (int i = n_global_long_options; options[i].name; i++) { - free(CONST_CAST(char *, options[i].name)); - } - free(options); - free(short_options); - - return error; -} - -static void -server_cmd_exit(struct unixctl_conn *conn, int argc OVS_UNUSED, - const char *argv[] OVS_UNUSED, void *exiting_) -{ - bool *exiting = exiting_; - *exiting = true; - unixctl_command_reply(conn, NULL); -} - -static void -server_cmd_run(struct unixctl_conn *conn, int argc, const char **argv_, - void *idl_) -{ - struct ovsdb_idl *idl = idl_; - struct ctl_command *commands = NULL; - struct shash local_options; - size_t n_commands = 0; - int n_options = 0; - char *error = NULL; - - /* Copy args so that getopt() can permute them. Leave last entry NULL. */ - char **argv = xcalloc(argc + 1, sizeof *argv); - for (int i = 0; i < argc; i++) { - argv[i] = xstrdup(argv_[i]); - } - - /* Reset global state. */ - oneline = false; - dry_run = false; - wait_type = NBCTL_WAIT_NONE; - force_wait = false; - timeout = 0; - table_style = table_style_default; - - /* Parse commands & options. */ - char *args = process_escape_args(argv); - shash_init(&local_options); - error = server_parse_options(argc, argv, &local_options, &n_options); - if (error) { - unixctl_command_reply_error(conn, error); - goto out; - } - error = ctl_parse_commands(argc - n_options, argv + n_options, - &local_options, &commands, &n_commands); - if (error) { - unixctl_command_reply_error(conn, error); - goto out; - } - VLOG(ctl_might_write_to_db(commands, n_commands) ? VLL_INFO : VLL_DBG, - "Running command %s", args); - - struct timer *wait_timeout = NULL; - struct timer wait_timeout_; - if (timeout) { - wait_timeout = &wait_timeout_; - timer_set_duration(wait_timeout, timeout * 1000); - } - - error = run_prerequisites(commands, n_commands, idl); - if (error) { - unixctl_command_reply_error(conn, error); - goto out; - } - error = main_loop(args, commands, n_commands, idl, wait_timeout); - if (error) { - unixctl_command_reply_error(conn, error); - goto out; - } - - struct ds output = DS_EMPTY_INITIALIZER; - table_format_reset(); - for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) { - if (c->table) { - table_format(c->table, &table_style, &output); - } else if (oneline) { - oneline_format(&c->output, &output); - } else { - ds_put_cstr(&output, ds_cstr_ro(&c->output)); - } - } - unixctl_command_reply(conn, ds_cstr_ro(&output)); - ds_destroy(&output); - -out: - free(error); - - struct ctl_command *c; - for (c = commands; c < &commands[n_commands]; c++) { - ds_destroy(&c->output); - table_destroy(c->table); - free(c->table); - shash_destroy_free_data(&c->options); - } - free(commands); - shash_destroy_free_data(&local_options); - free(args); - for (int i = 0; i < argc; i++) { - free(argv[i]); - } - free(argv); + return ovn_dbctl_main(argc, argv, &dbctl_options); } -static void -server_cmd_init(struct ovsdb_idl *idl, bool *exiting) -{ - unixctl_command_register("exit", "", 0, 0, server_cmd_exit, exiting); - unixctl_command_register("run", "", 0, INT_MAX, server_cmd_run, idl); -} - -static void -server_loop(struct ovsdb_idl *idl, int argc, char *argv[]) -{ - struct unixctl_server *server = NULL; - bool exiting = false; - - service_start(&argc, &argv); - daemonize_start(false); - - char *abs_unixctl_path = get_abs_unix_ctl_path(unixctl_path); - int error = unixctl_server_create(abs_unixctl_path, &server); - free(abs_unixctl_path); - - if (error) { - ctl_fatal("failed to create unixctl server (%s)", - ovs_retval_to_string(error)); - } - puts(unixctl_server_get_path(server)); - fflush(stdout); - server_cmd_init(idl, &exiting); - - for (;;) { - memory_run(); - if (memory_should_report()) { - struct simap usage = SIMAP_INITIALIZER(&usage); - - /* Nothing special to report yet. */ - memory_report(&usage); - simap_destroy(&usage); - } - - ovsdb_idl_run(idl); - if (!ovsdb_idl_is_alive(idl)) { - int retval = ovsdb_idl_get_last_error(idl); - ctl_fatal("%s: database connection failed (%s)", - db, ovs_retval_to_string(retval)); - } - - if (ovsdb_idl_has_ever_connected(idl)) { - daemonize_complete(); - } - unixctl_server_run(server); - - if (exiting) { - break; - } - - memory_wait(); - ovsdb_idl_wait(idl); - unixctl_server_wait(server); - poll_block(); - } - - unixctl_server_destroy(server); -} - -static void -nbctl_client(const char *socket_name, - const struct ovs_cmdl_parsed_option *parsed_options, size_t n, - int argc, char *argv[]) -{ - struct svec args = SVEC_EMPTY_INITIALIZER; - - for (const struct ovs_cmdl_parsed_option *po = parsed_options; - po < &parsed_options[n]; po++) { - optarg = po->arg; - switch (po->o->val) { - case OPT_DB: - VLOG_WARN("not using ovn-nbctl daemon because of %s option", - po->o->name); - svec_destroy(&args); - return; - - case OPT_NO_SYSLOG: - vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); - break; - - case 'h': - usage(); - exit(EXIT_SUCCESS); - - case OPT_COMMANDS: - ctl_print_commands(); - /* fall through */ - - case OPT_OPTIONS: - ctl_print_options(get_all_options()); - /* fall through */ - - case OPT_LEADER_ONLY: - case OPT_NO_LEADER_ONLY: - case OPT_SHUFFLE_REMOTES: - case OPT_NO_SHUFFLE_REMOTES: - case OPT_BOOTSTRAP_CA_CERT: - STREAM_SSL_CASES - OVN_DAEMON_OPTION_CASES - VLOG_INFO("using ovn-nbctl daemon, ignoring %s option", - po->o->name); - break; - - case 'u': - socket_name = optarg; - break; - - case 'V': - ovs_print_version(0, 0); - printf("DB Schema %s\n", nbrec_get_db_version()); - exit(EXIT_SUCCESS); - - case 't': - if (!str_to_uint(po->arg, 10, &timeout) || !timeout) { - ctl_fatal("value %s on -t or --timeout is invalid", po->arg); - } - break; - - VLOG_OPTION_HANDLERS - - case OPT_LOCAL: - default: - if (po->arg) { - svec_add_nocopy(&args, - xasprintf("--%s=%s", po->o->name, po->arg)); - } else { - svec_add_nocopy(&args, xasprintf("--%s", po->o->name)); - } - break; - } - } - - ovs_assert(socket_name && socket_name[0]); - - svec_add(&args, "--"); - for (int i = optind; i < argc; i++) { - svec_add(&args, argv[i]); - } - - ctl_timeout_setup(timeout); - - struct jsonrpc *client; - int error = unixctl_client_create(socket_name, &client); - if (error) { - ctl_fatal("%s: could not connect to ovn-nb daemon (%s); " - "unset OVN_NB_DAEMON to avoid using daemon", - socket_name, ovs_strerror(error)); - } - - char *cmd_result; - char *cmd_error; - error = unixctl_client_transact(client, "run", - args.n, args.names, - &cmd_result, &cmd_error); - if (error) { - ctl_fatal("%s: transaction error (%s)", - socket_name, ovs_strerror(error)); - } - svec_destroy(&args); - - int exit_status; - if (cmd_error) { - exit_status = EXIT_FAILURE; - fprintf(stderr, "%s: %s", program_name, cmd_error); - } else { - exit_status = EXIT_SUCCESS; - fputs(cmd_result, stdout); - } - free(cmd_result); - free(cmd_error); - jsonrpc_close(client); - exit(exit_status); -} From patchwork Sat Mar 27 00:31:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459072 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6ftb71Skz9sCD for ; Sat, 27 Mar 2021 11:32:23 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 700FD40689; Sat, 27 Mar 2021 00:32:21 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id SQsa37Wi5o-T; Sat, 27 Mar 2021 00:32:11 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTP id 0F5D040666; Sat, 27 Mar 2021 00:32:10 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 16B2CC0013; Sat, 27 Mar 2021 00:32:09 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id E196FC000B for ; Sat, 27 Mar 2021 00:32:06 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id AC02160DAC for ; Sat, 27 Mar 2021 00:32:06 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id e-VfTsfGobQq for ; Sat, 27 Mar 2021 00:32:02 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp3.osuosl.org (Postfix) with ESMTPS id F0D12605DA for ; Sat, 27 Mar 2021 00:32:01 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 5C5E2FF803; Sat, 27 Mar 2021 00:31:59 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:29 -0700 Message-Id: <20210327003147.2955790-4-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Ben Pfaff Subject: [ovs-dev] [PATCH ovn 03/21] ovn-sbctl: Add daemon support. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Also rewrite the manpage and convert it to XML for consistency with ovn-nbctl, and add tests. Signed-off-by: Ben Pfaff --- NEWS | 2 + manpages.mk | 17 - tests/ovn-sbctl.at | 76 +++-- utilities/automake.mk | 7 +- utilities/ovn-dbctl.c | 24 +- utilities/ovn-dbctl.h | 3 +- utilities/ovn-nbctl.c | 1 + utilities/ovn-sbctl.8.in | 317 ------------------ utilities/ovn-sbctl.8.xml | 583 +++++++++++++++++++++++++++++++++ utilities/ovn-sbctl.c | 670 +++++++------------------------------- 10 files changed, 785 insertions(+), 915 deletions(-) delete mode 100644 utilities/ovn-sbctl.8.in create mode 100644 utilities/ovn-sbctl.8.xml diff --git a/NEWS b/NEWS index 530c5d42fe85..5048433148b8 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ Post-v21.03.0 (This may take testing and tuning to be effective.) This version of OVN requires DDLog 0.36. - Introduce ovn-controller incremetal processing engine statistics + - ovn-sbctl can now run as a daemon (long-lived, background process). + See ovn-sbctl(8) for details. OVN v21.03.0 - 12 Mar 2021 ------------------------- diff --git a/manpages.mk b/manpages.mk index 44e544681424..3334b38f943d 100644 --- a/manpages.mk +++ b/manpages.mk @@ -10,20 +10,3 @@ lib/common-syn.man: lib/common.man: lib/ovs.tmac: -utilities/ovn-sbctl.8: \ - utilities/ovn-sbctl.8.in \ - lib/common.man \ - lib/db-ctl-base.man \ - lib/ovs.tmac \ - lib/ssl-bootstrap.man \ - lib/ssl.man \ - lib/table.man \ - lib/vlog.man -utilities/ovn-sbctl.8.in: -lib/common.man: -lib/db-ctl-base.man: -lib/ovs.tmac: -lib/ssl-bootstrap.man: -lib/ssl.man: -lib/table.man: -lib/vlog.man: diff --git a/tests/ovn-sbctl.at b/tests/ovn-sbctl.at index 2712cc15490c..9334762fd313 100644 --- a/tests/ovn-sbctl.at +++ b/tests/ovn-sbctl.at @@ -1,9 +1,14 @@ AT_BANNER([ovn-sbctl]) +OVS_START_SHELL_HELPERS # OVN_SBCTL_TEST_START m4_define([OVN_SBCTL_TEST_START], - [dnl Create databases (ovn-nb, ovn-sb). - AT_KEYWORDS([ovn]) + [AT_KEYWORDS([ovn]) + AT_CAPTURE_FILE([ovsdb-server.log]) + AT_CAPTURE_FILE([ovn-northd.log]) + ovn_sbctl_test_start $1]) +ovn_sbctl_test_start() { + dnl Create databases (ovn-nb, ovn-sb). for daemon in ovn-nb ovn-sb; do AT_CHECK([ovsdb-tool create $daemon.db $abs_top_srcdir/${daemon}.ovsschema]) done @@ -15,27 +20,54 @@ m4_define([OVN_SBCTL_TEST_START], AT_CHECK([[sed < stderr ' /vlog|INFO|opened log file/d /ovsdb_server|INFO|ovsdb-server (Open vSwitch)/d']]) - AT_CAPTURE_FILE([ovsdb-server.log]) dnl Start ovn-northd. AT_CHECK([ovn-northd --detach --no-chdir --pidfile --log-file --ovnnb-db=unix:$OVS_RUNDIR/ovnnb_db.sock --ovnsb-db=unix:$OVS_RUNDIR/ovnsb_db.sock], [0], [], [stderr]) on_exit "kill `cat ovn-northd.pid`" AT_CHECK([[sed < stderr ' /vlog|INFO|opened log file/d']]) - AT_CAPTURE_FILE([ovn-northd.log]) -]) + + AS_CASE([$1], + [daemon], + [export OVN_SB_DAEMON=$(ovn-sbctl --pidfile --detach --no-chdir --log-file -vsocket_util:off) + on_exit "kill `cat ovn-sbctl.pid`"], + [direct], [], + [*], [AT_FAIL_IF(:)]) +} # OVN_SBCTL_TEST_STOP -m4_define([OVN_SBCTL_TEST_STOP], - [AT_CHECK([check_logs "$1"]) - OVS_APP_EXIT_AND_WAIT([ovn-northd]) - OVS_APP_EXIT_AND_WAIT_BY_TARGET([$OVS_RUNDIR/ovnnb_db.ctl], [$OVS_RUNDIR/ovnnb_db.pid]) - OVS_APP_EXIT_AND_WAIT_BY_TARGET([$OVS_RUNDIR/ovnsb_db.ctl], [$OVS_RUNDIR/ovnsb_db.pid])]) +m4_define([OVN_SBCTL_TEST_STOP], [ovn_sbctl_test_stop]) +ovn_sbctl_test_stop() { + AT_CHECK([check_logs "$1"]) + OVS_APP_EXIT_AND_WAIT([ovn-northd]) + OVS_APP_EXIT_AND_WAIT_BY_TARGET([$OVS_RUNDIR/ovnnb_db.ctl], [$OVS_RUNDIR/ovnnb_db.pid]) + OVS_APP_EXIT_AND_WAIT_BY_TARGET([$OVS_RUNDIR/ovnsb_db.ctl], [$OVS_RUNDIR/ovnsb_db.pid]) +} +OVS_END_SHELL_HELPERS + +# OVN_SBCTL_TEST(NAME, TITLE, COMMANDS) +m4_define([OVN_SBCTL_TEST], + [OVS_START_SHELL_HELPERS + $1() { + $3 + } + OVS_END_SHELL_HELPERS + + AT_SETUP([ovn-sbctl - $2 - direct]) + OVN_SBCTL_TEST_START direct + $1 + OVN_SBCTL_TEST_STOP + AT_CLEANUP + + AT_SETUP([ovn-sbctl - $2 - daemon]) + OVN_SBCTL_TEST_START daemon + $1 + OVN_SBCTL_TEST_STOP + AT_CLEANUP]) dnl --------------------------------------------------------------------- -AT_SETUP([ovn-sbctl - chassis commands]) -OVN_SBCTL_TEST_START +OVN_SBCTL_TEST([ovn_sbctl_chassis_commands], [ovn-sbctl - chassis commands], [ ovn_init_db ovn-sb AT_CHECK([ovn-sbctl chassis-add ch0 geneve 1.2.3.4]) @@ -61,16 +93,14 @@ AT_CHECK([ovn-sbctl -f csv -d bare --no-headings --columns ip,type list encap | 1.2.3.5,vxlan ]) -OVN_SBCTL_TEST_STOP as ovn-sb OVS_APP_EXIT_AND_WAIT([ovsdb-server]) -AT_CLEANUP +as +]) dnl --------------------------------------------------------------------- -AT_SETUP([ovn-sbctl]) -OVN_SBCTL_TEST_START - +OVN_SBCTL_TEST([ovn_sbctl_commands], [ovn-sbctl], [ AT_CHECK([ovn-nbctl ls-add br-test]) AT_CHECK([ovn-nbctl lsp-add br-test vif0]) AT_CHECK([ovn-nbctl lsp-set-addresses vif0 f0:ab:cd:ef:01:02]) @@ -131,20 +161,14 @@ mac : [[]] type : vtep options : {vtep_logical_switch=l0, vtep_physical_switch=p0} ]) - -OVN_SBCTL_TEST_STOP -AT_CLEANUP +]) dnl --------------------------------------------------------------------- -AT_SETUP([ovn-sbctl - connection]) -OVN_SBCTL_TEST_START - +OVN_SBCTL_TEST([ovn_sbctl_connection], [ovn-sbctl - connection], [ AT_CHECK([ovn-sbctl --inactivity-probe=30000 set-connection ptcp:6641:127.0.0.1 punix:$OVS_RUNDIR/ovnsb_db.sock]) AT_CHECK([ovn-sbctl list connection | grep inactivity_probe], [0], [dnl inactivity_probe : 30000 inactivity_probe : 30000 ]) - -OVN_SBCTL_TEST_STOP -AT_CLEANUP +]) \ No newline at end of file diff --git a/utilities/automake.mk b/utilities/automake.mk index 50c0cfded018..a03892f2055a 100644 --- a/utilities/automake.mk +++ b/utilities/automake.mk @@ -14,7 +14,6 @@ man_MANS += \ utilities/ovn-appctl.8 MAN_ROOTS += \ - utilities/ovn-sbctl.8.in \ utilities/ovn-detrace.1.in # Docker drivers @@ -30,6 +29,7 @@ EXTRA_DIST += \ utilities/ovn-docker-overlay-driver.in \ utilities/ovn-docker-underlay-driver.in \ utilities/ovn-nbctl.8.xml \ + utilities/ovn-sbctl.8.xml \ utilities/ovn-ic-nbctl.8.xml \ utilities/ovn-ic-sbctl.8.xml \ utilities/ovn-appctl.8.xml \ @@ -79,7 +79,10 @@ utilities_ovn_nbctl_LDADD = lib/libovn.la $(OVSDB_LIBDIR)/libovsdb.la $(OVS_LIBD # ovn-sbctl bin_PROGRAMS += utilities/ovn-sbctl -utilities_ovn_sbctl_SOURCES = utilities/ovn-sbctl.c +utilities_ovn_sbctl_SOURCES = \ + utilities/ovn-dbctl.c \ + utilities/ovn-dbctl.h \ + utilities/ovn-sbctl.c utilities_ovn_sbctl_LDADD = lib/libovn.la $(OVSDB_LIBDIR)/libovsdb.la $(OVS_LIBDIR)/libopenvswitch.la # ovn-ic-nbctl diff --git a/utilities/ovn-dbctl.c b/utilities/ovn-dbctl.c index 5a41a21ce5c9..dc82355abc12 100644 --- a/utilities/ovn-dbctl.c +++ b/utilities/ovn-dbctl.c @@ -327,7 +327,8 @@ enum { }; static char * OVS_WARN_UNUSED_RESULT -handle_main_loop_option(int opt, const char *arg, bool *handled) +handle_main_loop_option(const struct ovn_dbctl_options *dbctl_options, + int opt, const char *arg, bool *handled) { ovs_assert(handled); *handled = true; @@ -338,11 +339,16 @@ handle_main_loop_option(int opt, const char *arg, bool *handled) break; case OPT_NO_WAIT: + if (!dbctl_options->allow_wait) { + return xstrdup("--no-wait not supported"); + } wait_type = NBCTL_WAIT_NONE; break; case OPT_WAIT: - if (!strcmp(arg, "none")) { + if (!dbctl_options->allow_wait) { + return xstrdup("--wait not supported"); + } else if (!strcmp(arg, "none")) { wait_type = NBCTL_WAIT_NONE; } else if (!strcmp(arg, "sb")) { wait_type = NBCTL_WAIT_SB; @@ -355,6 +361,9 @@ handle_main_loop_option(int opt, const char *arg, bool *handled) break; case OPT_PRINT_WAIT_TIME: + if (!dbctl_options->allow_wait) { + return xstrdup("--print-wait-time not supported"); + } print_wait_time = true; break; @@ -486,7 +495,8 @@ apply_options_direct(const struct ovn_dbctl_options *dbctl_options, for (const struct ovs_cmdl_parsed_option *po = parsed_options; po < &parsed_options[n]; po++) { bool handled; - char *error = handle_main_loop_option(po->o->val, po->arg, &handled); + char *error = handle_main_loop_option(dbctl_options, + po->o->val, po->arg, &handled); if (error) { ctl_fatal("%s", error); } @@ -834,7 +844,8 @@ find_option_by_value(const struct option *options, int value) } static char * OVS_WARN_UNUSED_RESULT -server_parse_options(int argc, char *argv[], struct shash *local_options, +server_parse_options(const struct ovn_dbctl_options *dbctl_options, + int argc, char *argv[], struct shash *local_options, int *n_options_p) { static const struct option global_long_options[] = { @@ -865,7 +876,7 @@ server_parse_options(int argc, char *argv[], struct shash *local_options, } bool handled; - error = handle_main_loop_option(c, optarg, &handled); + error = handle_main_loop_option(dbctl_options, c, optarg, &handled); if (error) { goto out; } @@ -967,7 +978,8 @@ server_cmd_run(struct unixctl_conn *conn, int argc, const char **argv_, /* Parse commands & options. */ char *args = process_escape_args(argv); shash_init(&local_options); - error = server_parse_options(argc, argv, &local_options, &n_options); + error = server_parse_options(dbctl_options, + argc, argv, &local_options, &n_options); if (error) { unixctl_command_reply_error(conn, error); goto out; diff --git a/utilities/ovn-dbctl.h b/utilities/ovn-dbctl.h index 5accf3c5e028..a1fbede6b5ce 100644 --- a/utilities/ovn-dbctl.h +++ b/utilities/ovn-dbctl.h @@ -15,7 +15,7 @@ #ifndef OVN_DBCTL_H #define OVN_DBCTL_H 1 -/* ovn-nbctl infrastructure code. */ +/* Common code for ovn-sbctl and ovn-nbctl. */ #include #include "ovsdb-idl.h" @@ -31,6 +31,7 @@ enum nbctl_wait_type { struct ovn_dbctl_options { const char *db_version; /* Database schema version. */ const char *default_db; /* Default database remote. */ + bool allow_wait; /* Allow --wait and related options? */ /* Names of important environment variables. */ const char *options_env_var_name; /* OVN_??_OPTIONS. */ diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c index 877b39f07e92..b49dfd3ac290 100644 --- a/utilities/ovn-nbctl.c +++ b/utilities/ovn-nbctl.c @@ -5982,6 +5982,7 @@ main(int argc, char *argv[]) struct ovn_dbctl_options dbctl_options = { .db_version = nbrec_get_db_version(), .default_db = default_nb_db(), + .allow_wait = true, .options_env_var_name = "OVN_NBCTL_OPTIONS", .daemon_env_var_name = "OVN_NB_DAEMON", diff --git a/utilities/ovn-sbctl.8.in b/utilities/ovn-sbctl.8.in deleted file mode 100644 index 153e72e6c28d..000000000000 --- a/utilities/ovn-sbctl.8.in +++ /dev/null @@ -1,317 +0,0 @@ -.\" -*- nroff -*- -.so lib/ovs.tmac -.TH ovn\-sbctl 8 "@VERSION@" "OVN" "OVN Manual" -.\" This program's name: -.ds PN ovn\-sbctl -. -.SH NAME -ovn\-sbctl \- utility for querying and configuring \fBOVN_Southbound\fR database -. -.SH SYNOPSIS -\fBovn\-sbctl\fR [\fIoptions\fR] \fB\-\-\fR [\fIoptions\fR] \fIcommand -\fR[\fIargs\fR] [\fB\-\-\fR [\fIoptions\fR] \fIcommand \fR[\fIargs\fR]]... -. -.SH DESCRIPTION -The \fBovn\-sbctl\fR program configures the \fBOVN_Southbound\fR database -by providing a high\-level interface to its configuration database. See -\fBovn\-sb\fR(5) for comprehensive documentation of the database schema. -.PP -\fBovn\-sbctl\fR connects to an \fBovsdb\-server\fR process that -maintains an OVN_Southbound configuration database. Using this -connection, it queries and possibly applies changes to the database, -depending on the supplied commands. -.PP -\fBovn\-sbctl\fR can perform any number of commands in a single run, -implemented as a single atomic transaction against the database. -.PP -The \fBovn\-sbctl\fR command line begins with global options (see -\fBOPTIONS\fR below for details). The global options are followed by -one or more commands. Each command should begin with \fB\-\-\fR by -itself as a command-line argument, to separate it from the following -commands. (The \fB\-\-\fR before the first command is optional.) The -command -itself starts with command-specific options, if any, followed by the -command name and any arguments. -. -.SH OPTIONS -. -The following options affect the behavior of \fBovn\-sbctl\fR as a -whole. Some individual commands also accept their own options, which -are given just before the command name. If the first command on the -command line has options, then those options must be separated from -the global options by \fB\-\-\fR. -. -.IP "\fB\-\-db=\fIserver\fR" -The OVSDB database remote to contact. If the \fBOVN_SB_DB\fR -environment variable is set, its value is used as the default. -Otherwise, the default is \fBunix:@RUNDIR@/ovnsb_db.sock\fR, but this -default is unlikely to be useful outside of single-machine OVN test -environments. -.IP -\fIserver\fR may be an OVSDB active or passive connection method, -e.g. \fBssl:192.168.10.5:6640\fR, as described in \fBovsdb\fR(7). -. -.IP "\fB\-\-leader\-only\fR" -.IQ "\fB\-\-no\-leader\-only\fR" -By default, or with \fB\-\-leader\-only\fR, when the database server -is a clustered database, \fBovn\-sbctl\fR will avoid servers other -than the cluster leader. This ensures that any data that -\fBovn\-sbctl\fR reads and reports is up-to-date. With -\fB\-\-no\-leader\-only\fR, \fBovn\-sbctl\fR will use any server in -the cluster, which means that for read-only transactions it can report -and act on stale data (transactions that modify the database are -always serialized even with \fB\-\-no\-leader\-only\fR). Refer to -\fBUnderstanding Cluster Consistency\fR in \fBovsdb\fR(7) for more -information. -. -.IP "\fB\-\-no\-syslog\fR" -By default, \fBovn\-sbctl\fR logs its arguments and the details of any -changes that it makes to the system log. This option disables this -logging. -.IP -This option is equivalent to \fB\-\-verbose=sbctl:syslog:warn\fR. -. -.IP "\fB\-\-oneline\fR" -Modifies the output format so that the output for each command is printed -on a single line. New-line characters that would otherwise separate -lines are printed as \fB\\n\fR, and any instances of \fB\\\fR that -would otherwise appear in the output are doubled. -Prints a blank line for each command that has no output. -This option does not affect the formatting of output from the -\fBlist\fR or \fBfind\fR commands; see \fBTable Formatting Options\fR -below. -. -.IP "\fB\-\-dry\-run\fR" -Prevents \fBovn\-sbctl\fR from actually modifying the database. -. -.IP "\fB\-t \fIsecs\fR" -.IQ "\fB\-\-timeout=\fIsecs\fR" -By default, or with a \fIsecs\fR of \fB0\fR, \fBovn\-sbctl\fR waits -forever for a response from the database. This option limits runtime -to approximately \fIsecs\fR seconds. If the timeout expires, -\fBovn\-sbctl\fR will exit with a \fBSIGALRM\fR signal. (A timeout -would normally happen only if the database cannot be contacted, or if -the system is overloaded.) -. -.IP "\fBOVN_SBCTL_OPTIONS\fR" -User can set one or more options using \fBOVN_SBCTL_OPTIONS\fR environment -variable. Under the Bourne shell this might be done like this: -export \fBOVN_SBCTL_OPTIONS\fR"="--db=unix:sb1.ovsdb --no-leader-only". -However user can still over-ride environment options by passing different -options in cli. When the environment variable is no longer needed, unset it, -e.g.: unset \fBOVN_SBCTL_OPTIONS\fR" -. -.so lib/vlog.man -.so lib/common.man -. -.SS "Table Formatting Options" -These options control the format of output from the \fBlist\fR and -\fBfind\fR commands. -.so lib/table.man -. -.SS "Public Key Infrastructure Options" -.so lib/ssl-bootstrap.man -.so lib/ssl.man -. -.SH COMMANDS -The commands implemented by \fBovn\-sbctl\fR are described in the -sections below. -.SS "OVN_Southbound Commands" -These commands work with an \fBOVN_Southbound\fR database as a whole. -. -.IP "\fBinit\fR" -Initializes the database, if it is empty. If the database has already -been initialized, this command has no effect. -. -.IP "\fBshow\fR" -Prints a brief overview of the database contents. -. -.SS "Chassis Commands" -These commands manipulate \fBOVN_Southbound\fR chassis. -. -.IP "[\fB\-\-may\-exist\fR] \fBchassis\-add \fIchassis\fR \fIencap-type\fR \fIencap-ip\fR" -Creates a new chassis named \fIchassis\fR. \fIencap-type\fR is a -comma-separated list of tunnel types. The chassis will have -one encap entry for each specified tunnel type with \fIencap-ip\fR -as the destination IP for each. -.IP -Without \fB\-\-may\-exist\fR, attempting to create a chassis that -exists is an error. With \fB\-\-may\-exist\fR, this command does -nothing if \fIchassis\fR already exists. -. -.IP "[\fB\-\-if\-exists\fR] \fBchassis\-del \fIchassis\fR" -Deletes \fIchassis\fR and its \fIencaps\fR and \fIgateway_ports\fR. -.IP -Without \fB\-\-if\-exists\fR, attempting to delete a chassis that does -not exist is an error. With \fB\-\-if\-exists\fR, attempting to -delete a chassis that does not exist has no effect. -. -.SS "Port binding Commands" -. -These commands manipulate \fBOVN_Southbound\fR port bindings. -. -.IP "[\fB\-\-may\-exist\fR] \fBlsp\-bind \fIlogical-port\fR \fIchassis\fR" -Binds the logical port named \fIlogical-port\fR to \fIchassis\fR. -.IP -Without \fB\-\-may\-exist\fR, attempting to bind a logical port that -has already been bound is an error. With \fB\-\-may\-exist\fR, this -command does nothing if \fIlogical-port\fR has already been bound to -a chassis. -. -.IP "[\fB\-\-if\-exists\fR] \fBlsp\-unbind\fR \fIlogical-port\fR" -Resets the binding of \fIlogical-port\fR to \fINULL\fR. -.IP -Without \fB\-\-if\-exists\fR, attempting to unbind a logical port -that is not bound is an error. With \fB\-\-if\-exists\fR, attempting -to unbind logical port that is not bound has no effect. -. -.SS "Logical Flow Commands" -. -.IP "[\fB\-\-uuid\fR] [\fB\-\-ovs\fR[\fB=\fIremote\fR]] [\fB\-\-stats\fR] [\fB\-\-vflows\fR] \fBlflow\-list\fR [\fIlogical-datapath\fR] [\fIlflow\fR...]" -List logical flows. If \fIlogical-datapath\fR is specified, only list -flows for that logical datapath. The \fIlogical-datapath\fR may be -given as a UUID or as a datapath name (reporting an error if multiple -datapaths have the same name). -.IP -If at least one \fIlflow\fR is given, only matching logical flows, if -any, are listed. Each \fIlflow\fR may be specified as a UUID or the -first few characters of a UUID, optionally prefixed by \fB0x\fR. -(Because \fBovn\-controller\fR sets OpenFlow flow cookies to the first -32 bits of the corresponding logical flow's UUID, this makes it easy -to look up the logical flow that generated a particular OpenFlow -flow.) -.IP -If \fB\-\-uuid\fR is specified, the output includes the first 32 bits -of each logical flow's UUID. This makes it easier to find the -OpenFlow flows that correspond to a given logical flow. -.IP -If \fB\-\-ovs\fR is included, \fBovn\-sbctl\fR attempts to obtain and -display the OpenFlow flows that correspond to each OVN logical flow. -To do so, \fBovn\-sbctl\fR connects to \fIremote\fR (by default, -\fBunix:@RUNDIR@/br-int.mgmt\fR) over OpenFlow and retrieves the -flows. If \fIremote\fR is specified, it must be an active OpenFlow -connection method described in \fBovsdb\fR(7). Please see the -discussion of the similar \fB\-\-ovs\fR option in \fBovn-trace\fR(8) -for more information about the OpenFlow flow output. -.IP -By default, OpenFlow flow output includes only match and actions. Add -\fB\-\-stats\fR to include all OpenFlow information, such as packet -and byte counters, duration, and timeouts. -.IP -If \fB\-\-vflows\fR is included, other southbound database records directly -used for generating OpenFlow flows are also listed. This includes: -\fIport-bindings\fR, \fImac-bindings\fR, \fImulticast-groups\fR, -\fIchassis\fR. The \fB\-\-ovs\fR and \fB\-\-stats\fR can also be used in -conjunction with \fB\-\-vflows\fR. -. -.IP "[\fB\-\-uuid\fR] \fBdump\-flows\fR [\fIlogical-datapath\fR]" -Alias for \fBlflow\-list\fB. -. -.SS "Remote Connectivity Commands" -. -These commands manipulate the \fBconnections\fR column in the \fBSB_Global\fR -table and rows in the \fBConnection\fR table. When \fBovsdb\-server\fR -is configured to use the \fBconnections\fR column for OVSDB connections, -this allows the administrator to use \fBovn\-sbctl\fR to configure database -connections. -. -.IP "\fBget\-connection\fR" -Prints the configured connection(s). -. -.IP "\fBdel\-connection\fR" -Deletes the configured connection(s). -. -.IP "\fBset\-connection\fR [\fIaccess\-specifier\fR] \fItarget\fR\&..." -Sets the configured manager target or targets. Each \fItarget\fR may -may be an OVSDB active or passive connection method, -e.g. \fBpssl:6640\fR, as described in \fBovsdb\fR(7), -optionally preceded by an optional access-specifier (\fBread\-only\fR or -\fBread\-write\fR). -If provided, the effect of the access specifier persists for subsequent -targets until changed by another access specifier. -. -.SS "SSL Configuration" -When \fBovsdb\-server\fR is configured to connect using SSL, the -following parameters are required: -.TP -\fIprivate-key\fR -Specifies a PEM file containing the private key used for SSL connections. -.TP -\fIcertificate\fR -Specifies a PEM file containing a certificate, signed by the -certificate authority (CA) used by the connection peers, that -certifies the private key, identifying a trustworthy peer. -.TP -\fIca-cert\fR -Specifies a PEM file containing the CA certificate used to verify that -the connection peers are trustworthy. -.PP -These SSL settings apply to all SSL connections made by the southbound -database server. -. -.IP "\fBget\-ssl\fR" -Prints the SSL configuration. -. -.IP "\fBdel\-ssl\fR" -Deletes the current SSL configuration. -. -.IP "[\fB\-\-bootstrap\fR] \fBset\-ssl\fR \fIprivate-key\fR \fIcertificate\fR \fIca-cert\fR [\fIssl-protocol-list\fR [\fIssl-cipher-list\fR]]" -Sets the SSL configuration. The \fB\-\-bootstrap\fR option is described -below. -. -.ST "CA Certificate Bootstrap" -.PP -Ordinarily, all of the files named in the SSL configuration must exist -before SSL connectivity can be used. However, if the \fIca-cert\fR file -does not exist and the \fB\-\-bootstrap\fR -option is given, then \fBovsdb\-server\fR will attempt to obtain the -CA certificate from the target on its first SSL connection and -save it to the named PEM file. If it is successful, it will -immediately drop the connection and reconnect, and from then on all -SSL connections must be authenticated by a certificate signed by the -CA certificate thus obtained. -.PP -\fBThis option exposes the SSL connection to a man-in-the-middle -attack obtaining the initial CA certificate\fR, but it may be useful -for bootstrapping. -.PP -This option is only useful if the SSL peer sends its CA certificate -as part of the SSL certificate chain. The SSL protocol does not -require the controller to send the CA certificate. -. -.SS "Database Commands" -. -These commands query and modify the contents of \fBovsdb\fR tables. -They are a slight abstraction of the \fBovsdb\fR interface and as such -they operate at a lower level than other \fBovs\-sbctl\fR commands. -.PP -.ST "Identifying Tables, Records, and Columns" -.PP -Each of these commands has a \fItable\fR parameter to identify a table -within the database. Many of them also take a \fIrecord\fR parameter -that identifies a particular record within a table. The \fIrecord\fR -parameter may be the UUID for a record, and many tables offer -additional ways to identify records. Some commands also take -\fIcolumn\fR parameters that identify a particular field within the -records in a table. -.PP -For a list of tables and their columns, see \fBovn\-sb\fR(5) or -see the table listing from the \fB--help\fR option. -.PP -Record names must be specified in full and with correct -capitalization, except that UUIDs may be abbreviated to their first 4 -(or more) hex digits, as long as that is unique within the table. -Names of tables and columns are not case-sensitive, and \fB\-\fR and -\fB_\fR are treated interchangeably. Unique abbreviations of table -and column names are acceptable, e.g. \fBaddr\fR or \fBa\fR is -sufficient to identify the \fBAddress_Set\fR table. -. -.so lib/db-ctl-base.man -.SH "EXIT STATUS" -.IP "0" -Successful program execution. -.IP "1" -Usage, syntax, or configuration file error. -.SH "SEE ALSO" -. -.BR ovn\-sb (5). diff --git a/utilities/ovn-sbctl.8.xml b/utilities/ovn-sbctl.8.xml new file mode 100644 index 000000000000..948933392e01 --- /dev/null +++ b/utilities/ovn-sbctl.8.xml @@ -0,0 +1,583 @@ + + +

Name

+

ovn-sbctl -- Open Virtual Network southbound db management utility

+ +

Synopsis

+

ovn-sbctl [options] command [arg...]

+ +

Description

+ +

+ The ovn-sbctl program configures the + OVN_Southbound database by providing a high-level interface + to its configuration database. See ovn-sb(5) for + comprehensive documentation of the database schema. +

+ +

+ ovn-sbctl connects to an ovsdb-server process + that maintains an OVN_Southbound configuration database. Using this + connection, it queries and possibly applies changes to the database, + depending on the supplied commands. +

+ +

+ ovn-sbctl can perform any number of commands in a single + run, implemented as a single atomic transaction against the database. +

+ +

+ The ovn-sbctl command line begins with global options (see + OPTIONS below for details). The global options are followed + by one or more commands. Each command should begin with -- + by itself as a command-line argument, to separate it from the following + commands. (The -- before the first command is optional.) + The command itself starts with command-specific options, if any, followed + by the command name and any arguments. +

+ +

Daemon Mode

+ +

+ When it is invoked in the most ordinary way, ovn-sbctl + connects to an OVSDB server that hosts the southbound database, retrieves + a partial copy of the database that is complete enough to do its work, + sends a transaction request to the server, and receives and processes the + server's reply. In common interactive use, this is fine, but if the + database is large, the step in which ovn-sbctl retrieves a + partial copy of the database can take a long time, which yields poor + performance overall. +

+ +

+ To improve performance in such a case, ovn-sbctl offers a + "daemon mode," in which the user first starts ovn-sbctl + running in the background and afterward uses the daemon to execute + operations. Over several ovn-sbctl command invocations, + this performs better overall because it retrieves a copy of the database + only once at the beginning, not once per program run. +

+ +

+ Use the --detach option to start an ovn-sbctl + daemon. With this option, ovn-sbctl prints the name of a + control socket to stdout. The client should save this name in + environment variable OVN_SB_DAEMON. Under the Bourne shell + this might be done like this: +

+ +
+      export OVN_SB_DAEMON=$(ovn-sbctl --pidfile --detach)
+    
+ +

+ When OVN_SB_DAEMON is set, ovn-sbctl + automatically and transparently uses the daemon to execute its commands. +

+ +

+ When the daemon is no longer needed, kill it and unset the environment + variable, e.g.: +

+ +
+      kill $(cat $OVN_RUNDIR/ovn-sbctl.pid)
+      unset OVN_SB_DAEMON
+    
+ +

+ When using daemon mode, an alternative to the OVN_SB_DAEMON + environment variable is to specify a path for the Unix socket. When + starting the ovn-sbctl daemon, specify the -u option with a + full path to the location of the socket file. Here is an exmple: +

+ +
+      ovn-sbctl --detach -u /tmp/mysock.ctl
+    
+ +

+ Then to connect to the running daemon, use the -u option + with the full path to the socket created when the daemon was started: +

+ +
+      ovn-sbctl -u /tmp/mysock.ctl show
+    
+ +

+ Daemon mode is experimental. +

+ +

Daemon Commands

+ +

+ Daemon mode is internally implemented using the same mechanism used by + ovs-appctl. One may also use ovs-appctl + directly with the following commands: +

+ +
+
+ run [options] command + [arg...] [-- [options] + command [arg...] ...] +
+
+ Instructs the daemon process to run one or more ovn-sbctl + commands described above and reply with the results of running these + commands. Accepts the --no-wait, --wait, + --timeout, --dry-run, --oneline, + and the options described under Table Formatting Options + in addition to the the command-specific options. +
+ +
exit
+
Causes ovn-sbctl to gracefully terminate.
+
+ +

Options

+ +

+ The options listed below affect the behavior of ovn-sbctl as + a whole. Some individual commands also accept their own options, which + are given just before the command name. If the first command on the + command line has options, then those options must be separated from the + global options by --. +

+ +

+ ovn-sbctl also accepts options from the + OVN_SBCTL_OPTIONS environment variable, in the same format as + on the command line. Options from the command line override those in the + environment. +

+ +
+
--db database
+
+ The OVSDB database remote to contact. If the OVN_SB_DB + environment variable is set, its value is used as the default. + Otherwise, the default is unix:@RUNDIR@/ovnsb_db.sock, but + this default is unlikely to be useful outside of single-machine OVN + test environments. +
+ +
--leader-only
+
--no-leader-only
+
+ By default, or with --leader-only, when the database + server is a clustered database, ovn-sbctl will avoid + servers other than the cluster leader. This ensures that any data that + ovn-sbctl reads and reports is up-to-date. With + --no-leader-only, ovn-sbctl will use any + server in the cluster, which means that for read-only transactions it + can report and act on stale data (transactions that modify the database + are always serialized even with --no-leader-only). Refer + to Understanding Cluster Consistency in + ovsdb(7) for more information. +
+ +
--shuffle-remotes
+
--no-shuffle-remotes
+
+ By default, or with --shuffle-remotes, when there are + multiple remotes specified in the OVSDB connection string specified by + --db or the OVN_SB_DB environment variable, the + order of the remotes will be shuffled before the client tries to + connect. The remotes will be shuffled only once to a new order before + the first connection attempt. The following retries, if any, will + follow the same new order. The default behavior is to make sure + clients of a clustered database can distribute evenly to all memembers + of the cluster. With --no-shuffle-remotes, + ovn-sbctl will use the original order specified in the + connection string to connect. This allows user to specify the + preferred order, which is particularly useful for testing. +
+ +
--no-syslog
+
+

+ By default, ovn-sbctl logs its arguments and the details + of any changes that it makes to the system log. This option disables + this logging. +

+ +

+ This option is equivalent to + --verbose=sbctl:syslog:warn. +

+
+ +
--oneline
+
+ Modifies the output format so that the output for each command is + printed on a single line. New-line characters that would otherwise + separate lines are printed as \fB\\n\fR, and any instances of \fB\\\fR + that would otherwise appear in the output are doubled. Prints a blank + line for each command that has no output. This option does not affect + the formatting of output from the list or + find commands; see Table Formatting Options + below. +
+ +
--dry-run
+
+ Prevents ovn-sbctl from actually modifying the database. +
+ +
-t secs
+
--timeout=secs
+
+ By default, or with a secs of 0, + ovn-sbctl waits forever for a response from the database. + This option limits runtime to approximately secs seconds. + If the timeout expires, ovn-sbctl will exit with a + SIGALRM signal. (A timeout would normally happen only if + the database cannot be contacted, or if the system is overloaded.) +
+
+ +

Daemon Options

+ + +

Logging options

+ + +

Table Formatting Options

+ These options control the format of output from the list and + find commands. + + +

PKI Options

+

+ PKI configuration is required to use SSL for the connection to the + database. +

+ + + +

Other Options

+ + + +

Commands

+ +

+ The following sections describe the commands that ovn-sbctl + supports. +

+ +

OVN_Southbound Commands

+ +

+ These commands work with an OVN_Southbound database as a + whole. +

+ +
+
init
+
+ Initializes the database, if it is empty. If the database has already + been initialized, this command has no effect. +
+ +
show
+
+ Prints a brief overview of the database contents. +
+
+ +

Chassis Commands

+ +

+ These commands manipulate OVN_Southbound chassis. +

+ +
+
[--may-exist] chassis-add chassis encap-type encap-ip
+ +
+

+ Creates a new chassis named chassis. + encap-type is a comma-separated list of tunnel types. The + chassis will have one encap entry for each specified tunnel type with + encap-ip as the destination IP for each. +

+ +

+ Without \fB\-\-may\-exist\fR, attempting to create a chassis that + exists is an error. With \fB\-\-may\-exist\fR, this command does + nothing if chassis already exists. +

+
+ +
[--if-exists] chassis-del chassis
+
+

+ Deletes chassis and its encaps and + gateway_ports. +

+ +

+ Without --if-exists, attempting to delete a chassis that + does not exist is an error. With --if-exists attempting + to delete a chassis that does not exist has no effect. +

+
+
+ +

Port Binding Commands

+ +

+ These commands manipulate OVN_Southbound port bindings. +

+ +
+
[--may-exist] lsp-bind logical-port chassis
+
+

+ Binds the logical port named logical-port to + chassis. +

+ +

+ Without --may-exist, attempting to bind a logical port + that has already been bound is an error. With + --may-exist, this command does nothing if + logical-port has already been bound to a chassis. +

+
+ +
[--if-exists] lsp-unbind logical-port
+
+

+ Removes the binding of logical-port. +

+ +

+ Without --if-exists, attempting to unbind a logical port + that is not bound is an error. With --if-exists, + attempting to unbind logical port that is not bound has no effect. +

+
+
+ +

Logical Flow Commands

+ +
+
[--uuid] [--ovs[=remote]] [--stats] [--vflows] lflow-list [logical-datapath] [lflow...]
+ +
+

+ List logical flows. If logical-datapath is specified, + only list flows for that logical datapath. The + logical-datapath may be given as a UUID or as a datapath + name (reporting an error if multiple datapaths have the same name). +

+ +

+ If at least one lflow is given, only matching logical + flows, if any, are listed. Each lflow may be specified as + a UUID or the first few characters of a UUID, optionally prefixed by + 0x. (Because ovn-controller sets OpenFlow + flow cookies to the first 32 bits of the corresponding logical flow's + UUID, this makes it easy to look up the logical flow that generated a + particular OpenFlow flow.) +

+ +

+ If --uuid is specified, the output includes the first 32 + bits of each logical flow's UUID. This makes it easier to find the + OpenFlow flows that correspond to a given logical flow. +

+ +

+ If --ovs is included, ovn-sbctl attempts to + obtain and display the OpenFlow flows that correspond to each OVN + logical flow. To do so, ovn-sbctl connects to + remote (by default, + unix:@RUNDIR@/br-int.mgmt) over OpenFlow and retrieves + the flows. If remote is specified, it must be an active + OpenFlow connection method described in ovsdb(7). + Please see the discussion of the similar --ovs option in + ovn-trace(8) for more information about the OpenFlow + flow output. +

+ +

+ By default, OpenFlow flow output includes only match and actions. + Add --stats to include all OpenFlow information, such as + packet and byte counters, duration, and timeouts. +

+ +

+ If --vflows is included, other southbound database + records directly used for generating OpenFlow flows are also + listed. This includes: port-bindings, + mac-bindings, multicast-groups, + chassis. The --ovs and --stats + can also be used in conjunction with --vflows. +

+
+ +
[--uuid] dump-flows [logical-datapath]
+
Alias for lflow-list.
+
+ +

Remote Connectivity Commands

+ +

+ These commands manipulate the connections column in the + SB_Global table and rows in the Connection + table. When ovsdb-server is configured to use the + connections column for OVSDB connections, this allows the + administrator to use \fBovn\-sbctl\fR to configure database connections. +

+ +
+
get-connection
+
+ Prints the configured connection(s). +
+ +
del-connection
+
+ Deletes the configured connection(s). +
+ +
[--inactivity-probe=msecs] set-connection target...
+
+ Sets the configured manager target or targets. Use + --inactivity-probe=msecs to override the + default idle connection inactivity probe time. Use 0 to disable + inactivity probes. +
+
+ +

SSL Configuration Commands

+

+ When ovsdb-server is configured to connect using SSL, the + following parameters are required: +

+ +
+
private-key
+
+ Specifies a PEM file containing the private key used for SSL + connections. +
+ +
certificate
+
+ Specifies a PEM file containing a certificate, signed by the + certificate authority (CA) used by the connection peers, that + certifies the private key, identifying a trustworthy peer. +
+ +
ca-cert
+
+ Specifies a PEM file containing the CA certificate used to verify that + the connection peers are trustworthy. +
+
+ +

+ These SSL settings apply to all SSL connections made by the southbound + database server. +

+ +
+
get-ssl
+
+ Prints the SSL configuration. +
+ +
del-ssl
+
+ Deletes the current SSL configuration. +
+ +
[--bootstrap] set-ssl + private-key certificate ca-cert + [ssl-protocol-list [ssl-cipher-list]]
+
+ Sets the SSL configuration. +
+
+ +

Database Commands

+

+ These commands query and modify the contents of ovsdb + tables. They are a slight abstraction of the ovsdb + interface and as such they operate at a lower level than other + ovn-sbctl commands. +

+ +

Identifying Tables, Records, and Columns

+ +

+ Each of these commands has a table parameter to identify a + table within the database. Many of them also take a record + parameter that identifies a particular record within a table. The + record parameter may be the UUID for a record, which may be + abbreviated to its first 4 (or more) hex digits, as long as that is + unique. Many tables offer additional ways to identify records. Some + commands also take column parameters that identify a + particular field within the records in a table. +

+ +

+ For a list of tables and their columns, see ovn-sb(5) or + see the table listing from the --help option. +

+ +

+ Record names must be specified in full and with correct capitalization, + except that UUIDs may be abbreviated to their first 4 (or more) hex + digits, as long as that is unique within the table. Names of tables and + columns are not case-sensitive, and - and _ are + treated interchangeably. Unique abbreviations of table and column names + are acceptable, e.g. d or dhcp is sufficient + to identify the DHCP_Options table. +

+ + + +

Environment

+ +
+
OVN_SB_DAEMON
+
+ If set, this should name the Unix domain socket for an + ovn-sbctl server process. See Daemon Mode, + above, for more information. +
+ +
OVN_SBCTL_OPTIONS
+
+ If set, a set of options for ovn-sbctl to apply + automatically, in the same form as on the command line. +
+ +
OVN_SB_DB
+
+ If set, the default database to contact when the --db + option is not used. +
+
+ +

Exit Status

+
+
0
+
Successful program execution.
+ +
1
+
Usage, syntax, or network error.
+
+ +

See Also

+ ovn-sb(5). + +
diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c index e3aa7a68e680..197504fe4015 100644 --- a/utilities/ovn-sbctl.c +++ b/utilities/ovn-sbctl.c @@ -31,8 +31,10 @@ #include "command-line.h" #include "compiler.h" #include "db-ctl-base.h" +#include "daemon.h" #include "dirs.h" #include "fatal-signal.h" +#include "jsonrpc.h" #include "openvswitch/dynamic-string.h" #include "openvswitch/json.h" #include "openvswitch/ofp-actions.h" @@ -43,276 +45,45 @@ #include "openvswitch/vlog.h" #include "lib/ovn-sb-idl.h" #include "lib/ovn-util.h" +#include "memory.h" +#include "ovn-dbctl.h" #include "ovsdb-data.h" #include "ovsdb-idl.h" #include "openvswitch/poll-loop.h" #include "process.h" +#include "simap.h" #include "sset.h" #include "stream-ssl.h" #include "stream.h" #include "table.h" +#include "timer.h" #include "timeval.h" +#include "unixctl.h" #include "util.h" #include "svec.h" VLOG_DEFINE_THIS_MODULE(sbctl); -struct sbctl_context; - -/* --db: The database server to contact. */ -static const char *db; - -/* --oneline: Write each command's output as a single line? */ -static bool oneline; - -/* --dry-run: Do not commit any changes. */ -static bool dry_run; - -/* --timeout: Time to wait for a connection to 'db'. */ -static unsigned int timeout; - -/* Format for table output. */ -static struct table_style table_style = TABLE_STYLE_DEFAULT; - -/* The IDL we're using and the current transaction, if any. - * This is for use by sbctl_exit() only, to allow it to clean up. - * Other code should use its context arguments. */ -static struct ovsdb_idl *the_idl; -static struct ovsdb_idl_txn *the_idl_txn; -OVS_NO_RETURN static void sbctl_exit(int status); - -/* --leader-only, --no-leader-only: Only accept the leader in a cluster. */ -static int leader_only = true; - -static void sbctl_cmd_init(void); -OVS_NO_RETURN static void usage(void); -static void parse_options(int argc, char *argv[], struct shash *local_options); -static void run_prerequisites(struct ctl_command[], size_t n_commands, - struct ovsdb_idl *); -static bool do_sbctl(const char *args, struct ctl_command *, size_t n, - struct ovsdb_idl *); - -int -main(int argc, char *argv[]) +static void +sbctl_add_base_prerequisites(struct ovsdb_idl *idl, + enum nbctl_wait_type wait_type OVS_UNUSED) { - struct ovsdb_idl *idl; - struct ctl_command *commands; - struct shash local_options; - unsigned int seqno; - size_t n_commands; - - ovn_set_program_name(argv[0]); - fatal_ignore_sigpipe(); - vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); - vlog_set_levels_from_string_assert("reconnect:warn"); - - sbctl_cmd_init(); - - /* Check if options are set via env var. */ - char **argv_ = ovs_cmdl_env_parse_all(&argc, argv, - getenv("OVN_SBCTL_OPTIONS")); - - /* Parse command line. */ - char *args = process_escape_args(argv_); - shash_init(&local_options); - parse_options(argc, argv_, &local_options); - char *error = ctl_parse_commands(argc - optind, argv_ + optind, - &local_options, &commands, &n_commands); - if (error) { - ctl_fatal("%s", error); - } - VLOG(ctl_might_write_to_db(commands, n_commands) ? VLL_INFO : VLL_DBG, - "Called as %s", args); - - ctl_timeout_setup(timeout); - - /* Initialize IDL. */ - idl = the_idl = ovsdb_idl_create(db, &sbrec_idl_class, false, true); - ovsdb_idl_set_leader_only(idl, leader_only); - run_prerequisites(commands, n_commands, idl); - - /* Execute the commands. - * - * 'seqno' is the database sequence number for which we last tried to - * execute our transaction. There's no point in trying to commit more than - * once for any given sequence number, because if the transaction fails - * it's because the database changed and we need to obtain an up-to-date - * view of the database before we try the transaction again. */ - seqno = ovsdb_idl_get_seqno(idl); - for (;;) { - ovsdb_idl_run(idl); - if (!ovsdb_idl_is_alive(idl)) { - int retval = ovsdb_idl_get_last_error(idl); - ctl_fatal("%s: database connection failed (%s)", - db, ovs_retval_to_string(retval)); - } - - if (seqno != ovsdb_idl_get_seqno(idl)) { - seqno = ovsdb_idl_get_seqno(idl); - if (do_sbctl(args, commands, n_commands, idl)) { - break; - } - } - - if (seqno == ovsdb_idl_get_seqno(idl)) { - ovsdb_idl_wait(idl); - poll_block(); - } - } - - for (int i = 0; i < argc; i++) { - free(argv_[i]); - } - free(argv_); - free(args); - exit(EXIT_SUCCESS); + ovsdb_idl_add_table(idl, &sbrec_table_sb_global); } static void -parse_options(int argc, char *argv[], struct shash *local_options) +sbctl_pre_execute(struct ovsdb_idl *idl, struct ovsdb_idl_txn *txn, + enum nbctl_wait_type wait_type OVS_UNUSED) { - enum { - OPT_DB = UCHAR_MAX + 1, - OPT_ONELINE, - OPT_NO_SYSLOG, - OPT_DRY_RUN, - OPT_LOCAL, - OPT_COMMANDS, - OPT_OPTIONS, - OPT_BOOTSTRAP_CA_CERT, - VLOG_OPTION_ENUMS, - TABLE_OPTION_ENUMS, - SSL_OPTION_ENUMS, - }; - static const struct option global_long_options[] = { - {"db", required_argument, NULL, OPT_DB}, - {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, - {"dry-run", no_argument, NULL, OPT_DRY_RUN}, - {"oneline", no_argument, NULL, OPT_ONELINE}, - {"timeout", required_argument, NULL, 't'}, - {"help", no_argument, NULL, 'h'}, - {"commands", no_argument, NULL, OPT_COMMANDS}, - {"options", no_argument, NULL, OPT_OPTIONS}, - {"leader-only", no_argument, &leader_only, true}, - {"no-leader-only", no_argument, &leader_only, false}, - {"version", no_argument, NULL, 'V'}, - VLOG_LONG_OPTIONS, - STREAM_SSL_LONG_OPTIONS, - {"bootstrap-ca-cert", required_argument, NULL, OPT_BOOTSTRAP_CA_CERT}, - TABLE_LONG_OPTIONS, - {NULL, 0, NULL, 0}, - }; - const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; - char *tmp, *short_options; - - struct option *options; - size_t allocated_options; - size_t n_options; - size_t i; - - tmp = ovs_cmdl_long_options_to_short_options(global_long_options); - short_options = xasprintf("+%s", tmp); - free(tmp); - - /* We want to parse both global and command-specific options here, but - * getopt_long() isn't too convenient for the job. We copy our global - * options into a dynamic array, then append all of the command-specific - * options. */ - options = xmemdup(global_long_options, sizeof global_long_options); - allocated_options = ARRAY_SIZE(global_long_options); - n_options = n_global_long_options; - ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL); - - for (;;) { - int idx; - int c; - - c = getopt_long(argc, argv, short_options, options, &idx); - if (c == -1) { - break; - } - - switch (c) { - case OPT_DB: - db = optarg; - break; - - case OPT_ONELINE: - oneline = true; - break; - - case OPT_NO_SYSLOG: - vlog_set_levels(&this_module, VLF_SYSLOG, VLL_WARN); - break; - - case OPT_DRY_RUN: - dry_run = true; - break; - - case OPT_LOCAL: - if (shash_find(local_options, options[idx].name)) { - ctl_fatal("'%s' option specified multiple times", - options[idx].name); - } - shash_add_nocopy(local_options, - xasprintf("--%s", options[idx].name), - nullable_xstrdup(optarg)); - break; - - case 'h': - usage(); - - case OPT_COMMANDS: - ctl_print_commands(); - /* fall through */ - - case OPT_OPTIONS: - ctl_print_options(global_long_options); - /* fall through */ - - case 'V': - ovn_print_version(0, 0); - printf("DB Schema %s\n", sbrec_get_db_version()); - exit(EXIT_SUCCESS); - - case 't': - if (!str_to_uint(optarg, 10, &timeout) || !timeout) { - ctl_fatal("value %s on -t or --timeout is invalid", optarg); - } - break; - - VLOG_OPTION_HANDLERS - TABLE_OPTION_HANDLERS(&table_style) - STREAM_SSL_OPTION_HANDLERS - - case OPT_BOOTSTRAP_CA_CERT: - stream_ssl_set_ca_cert_file(optarg, true); - break; - - case '?': - exit(EXIT_FAILURE); - - default: - abort(); - - case 0: - break; - } - } - free(short_options); - - if (!db) { - db = default_sb_db(); - } - - for (i = n_global_long_options; options[i].name; i++) { - free(CONST_CAST(char *, options[i].name)); + const struct sbrec_sb_global *sb = sbrec_sb_global_first(idl); + if (!sb) { + /* XXX add verification that table is empty */ + sb = sbrec_sb_global_insert(txn); } - free(options); } static void -usage(void) +sbctl_usage(void) { printf("\ %s: OVN southbound DB management utility\n\ @@ -372,8 +143,12 @@ Other options:\n\ stream_usage("database", true, true, true); exit(EXIT_SUCCESS); } - +/* One should not use ctl_fatal() within commands because it will kill the + * daemon if we're in daemon mode. Use ctl_error() instead and return + * gracefully. */ +#define ctl_fatal dont_use_ctl_fatal_use_ctl_error_and_return + /* ovs-sbctl specific context. Inherits the 'struct ctl_context' as base. */ struct sbctl_context { struct ctl_context base; @@ -420,18 +195,20 @@ sbctl_context_invalidate_cache(struct ctl_context *ctx) shash_destroy_free_data(&sbctl_ctx->port_bindings); } -static void -sbctl_context_populate_cache(struct ctl_context *ctx) +/* Casts 'base' into 'struct sbctl_context' and initializes it if needed. */ +static struct sbctl_context * +sbctl_context_get(struct ctl_context *ctx) { - struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx); + struct sbctl_context *sbctl_ctx + = CONTAINER_OF(ctx, struct sbctl_context, base); + if (sbctl_ctx->cache_valid) { + return sbctl_ctx; + } + const struct sbrec_chassis *chassis_rec; const struct sbrec_port_binding *port_binding_rec; struct sset chassis, port_bindings; - if (sbctl_ctx->cache_valid) { - /* Cache is already populated. */ - return; - } sbctl_ctx->cache_valid = true; shash_init(&sbctl_ctx->chassis); shash_init(&sbctl_ctx->port_bindings); @@ -468,46 +245,63 @@ sbctl_context_populate_cache(struct ctl_context *ctx) bd); } sset_destroy(&port_bindings); + + return sbctl_ctx; +} + +static struct ctl_context * +sbctl_ctx_create(void) +{ + struct sbctl_context *sbctx = xmalloc(sizeof *sbctx); + *sbctx = (struct sbctl_context) { + .cache_valid = false, + }; + return &sbctx->base; } static void -check_conflicts(struct sbctl_context *sbctl_ctx, const char *name, - char *msg) +sbctl_ctx_destroy(struct ctl_context *ctx) { + sbctl_context_invalidate_cache(ctx); + free(ctx); +} + +static bool +check_conflicts(struct ctl_context *ctx, const char *name, char *msg) +{ + struct sbctl_context *sbctl_ctx = sbctl_context_get(ctx); if (shash_find(&sbctl_ctx->chassis, name)) { - ctl_fatal("%s because a chassis named %s already exists", - msg, name); + ctl_error(&sbctl_ctx->base, + "%s because a chassis named %s already exists", + msg, name); + return false; } free(msg); + + return true; } static struct sbctl_chassis * -find_chassis(struct sbctl_context *sbctl_ctx, const char *name, - bool must_exist) +find_chassis(struct ctl_context *ctx, const char *name, bool must_exist) { - struct sbctl_chassis *sbctl_ch; - - ovs_assert(sbctl_ctx->cache_valid); - - sbctl_ch = shash_find_data(&sbctl_ctx->chassis, name); + struct sbctl_context *sbctl_ctx = sbctl_context_get(ctx); + struct sbctl_chassis *sbctl_ch = shash_find_data(&sbctl_ctx->chassis, + name); if (must_exist && !sbctl_ch) { - ctl_fatal("no chassis named %s", name); + ctl_error(ctx, "no chassis named %s", name); } return sbctl_ch; } static struct sbctl_port_binding * -find_port_binding(struct sbctl_context *sbctl_ctx, const char *name, - bool must_exist) +find_port_binding(struct ctl_context *ctx, const char *name, bool must_exist) { - struct sbctl_port_binding *bd; - - ovs_assert(sbctl_ctx->cache_valid); - - bd = shash_find_data(&sbctl_ctx->port_bindings, name); + struct sbctl_context *sbctl_ctx = sbctl_context_get(ctx); + struct sbctl_port_binding *bd = shash_find_data(&sbctl_ctx->port_bindings, + name); if (must_exist && !bd) { - ctl_fatal("no port named %s", name); + ctl_error(&sbctl_ctx->base, "no port named %s", name); } return bd; @@ -588,7 +382,6 @@ sbctl_init(struct ctl_context *ctx OVS_UNUSED) static void cmd_chassis_add(struct ctl_context *ctx) { - struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx); bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; const char *ch_name, *encap_types, *encap_ip; @@ -596,17 +389,17 @@ cmd_chassis_add(struct ctl_context *ctx) encap_types = ctx->argv[2]; encap_ip = ctx->argv[3]; - sbctl_context_populate_cache(ctx); if (may_exist) { - struct sbctl_chassis *sbctl_ch; - - sbctl_ch = find_chassis(sbctl_ctx, ch_name, false); + struct sbctl_chassis *sbctl_ch = find_chassis(ctx, ch_name, false); if (sbctl_ch) { return; } } - check_conflicts(sbctl_ctx, ch_name, - xasprintf("cannot create a chassis named %s", ch_name)); + if (!check_conflicts(ctx, ch_name, + xasprintf("cannot create a chassis named %s", + ch_name))) { + return; + } struct sset encap_set; sset_from_delimited_string(&encap_set, encap_types, ","); @@ -642,8 +435,7 @@ cmd_chassis_del(struct ctl_context *ctx) bool must_exist = !shash_find(&ctx->options, "--if-exists"); struct sbctl_chassis *sbctl_ch; - sbctl_context_populate_cache(ctx); - sbctl_ch = find_chassis(sbctl_ctx, ctx->argv[1], must_exist); + sbctl_ch = find_chassis(ctx, ctx->argv[1], must_exist); if (sbctl_ch) { if (sbctl_ch->ch_cfg) { size_t i; @@ -672,17 +464,21 @@ cmd_lsp_bind(struct ctl_context *ctx) lport_name = ctx->argv[1]; ch_name = ctx->argv[2]; - sbctl_context_populate_cache(ctx); - sbctl_bd = find_port_binding(sbctl_ctx, lport_name, true); - sbctl_ch = find_chassis(sbctl_ctx, ch_name, true); + sbctl_bd = find_port_binding(ctx, lport_name, true); + if (!sbctl_ctx) { + return; + } + sbctl_ch = find_chassis(ctx, ch_name, true); + if (!sbctl_ch) { + return; + } if (sbctl_bd->bd_cfg->chassis) { - if (may_exist && sbctl_bd->bd_cfg->chassis == sbctl_ch->ch_cfg) { - return; - } else { - ctl_fatal("lport (%s) has already been binded to chassis (%s)", + if (!may_exist || sbctl_bd->bd_cfg->chassis != sbctl_ch->ch_cfg) { + ctl_error(ctx, "lport (%s) has already been binded to chassis (%s)", lport_name, sbctl_bd->bd_cfg->chassis->name); } + return; } sbrec_port_binding_set_chassis(sbctl_bd->bd_cfg, sbctl_ch->ch_cfg); sbrec_port_binding_set_up(sbctl_bd->bd_cfg, &up, 1); @@ -692,14 +488,12 @@ cmd_lsp_bind(struct ctl_context *ctx) static void cmd_lsp_unbind(struct ctl_context *ctx) { - struct sbctl_context *sbctl_ctx = sbctl_context_cast(ctx); bool must_exist = !shash_find(&ctx->options, "--if-exists"); struct sbctl_port_binding *sbctl_bd; char *lport_name; lport_name = ctx->argv[1]; - sbctl_context_populate_cache(ctx); - sbctl_bd = find_port_binding(sbctl_ctx, lport_name, must_exist); + sbctl_bd = find_port_binding(ctx, lport_name, must_exist); if (sbctl_bd) { sbrec_port_binding_set_chassis(sbctl_bd->bd_cfg, NULL); sbrec_port_binding_set_up(sbctl_bd->bd_cfg, NULL, 0); @@ -1123,7 +917,9 @@ cmd_lflow_list(struct ctl_context *ctx) char *error = ctl_get_row(ctx, &sbrec_table_datapath_binding, ctx->argv[1], false, &row); if (error) { - ctl_fatal("%s", error); + ctl_error(ctx, "%s", error); + free(error); + return; } datapath = (const struct sbrec_datapath_binding *)row; @@ -1136,8 +932,9 @@ cmd_lflow_list(struct ctl_context *ctx) for (size_t i = 1; i < ctx->argc; i++) { char *s = parse_partial_uuid(ctx->argv[i]); if (!s) { - ctl_fatal("%s is not a UUID or the beginning of a UUID", + ctl_error(ctx, "%s is not a UUID or the beginning of a UUID", ctx->argv[i]); + return; } ctx->argv[i] = s; } @@ -1272,12 +1069,15 @@ sbctl_ip_mcast_flush(struct ctl_context *ctx) char *error = ctl_get_row(ctx, &sbrec_table_datapath_binding, ctx->argv[1], false, &row); if (error) { - ctl_fatal("%s", error); + ctl_error(ctx, "%s", error); + free(error); + return; } dp = (const struct sbrec_datapath_binding *)row; if (!dp) { - ctl_fatal("%s is not a valid datapath", ctx->argv[1]); + ctl_error(ctx, "%s is not a valid datapath", ctx->argv[1]); + return; } sbctl_ip_mcast_flush_switch(ctx, dp); @@ -1564,248 +1364,6 @@ static const struct ctl_table_class tables[SBREC_N_TABLES] = { = {&sbrec_load_balancer_col_name, NULL, NULL}, }; - -static void -sbctl_context_init_command(struct sbctl_context *sbctl_ctx, - struct ctl_command *command) -{ - ctl_context_init_command(&sbctl_ctx->base, command); -} - -static void -sbctl_context_init(struct sbctl_context *sbctl_ctx, - struct ctl_command *command, struct ovsdb_idl *idl, - struct ovsdb_idl_txn *txn, - struct ovsdb_symbol_table *symtab) -{ - ctl_context_init(&sbctl_ctx->base, command, idl, txn, symtab, - sbctl_context_invalidate_cache); - sbctl_ctx->cache_valid = false; -} - -static void -sbctl_context_done_command(struct sbctl_context *sbctl_ctx, - struct ctl_command *command) -{ - ctl_context_done_command(&sbctl_ctx->base, command); -} - -static void -sbctl_context_done(struct sbctl_context *sbctl_ctx, - struct ctl_command *command) -{ - ctl_context_done(&sbctl_ctx->base, command); -} - -static void -run_prerequisites(struct ctl_command *commands, size_t n_commands, - struct ovsdb_idl *idl) -{ - ovsdb_idl_add_table(idl, &sbrec_table_sb_global); - - for (struct ctl_command *c = commands; c < &commands[n_commands]; c++) { - if (c->syntax->prerequisites) { - struct sbctl_context sbctl_ctx; - - ds_init(&c->output); - c->table = NULL; - - sbctl_context_init(&sbctl_ctx, c, idl, NULL, NULL); - (c->syntax->prerequisites)(&sbctl_ctx.base); - if (sbctl_ctx.base.error) { - ctl_fatal("%s", sbctl_ctx.base.error); - } - sbctl_context_done(&sbctl_ctx, c); - - ovs_assert(!c->output.string); - ovs_assert(!c->table); - } - } -} - -static bool -do_sbctl(const char *args, struct ctl_command *commands, size_t n_commands, - struct ovsdb_idl *idl) -{ - struct ovsdb_idl_txn *txn; - enum ovsdb_idl_txn_status status; - struct ovsdb_symbol_table *symtab; - struct sbctl_context sbctl_ctx; - struct ctl_command *c; - struct shash_node *node; - - txn = the_idl_txn = ovsdb_idl_txn_create(idl); - if (dry_run) { - ovsdb_idl_txn_set_dry_run(txn); - } - - ovsdb_idl_txn_add_comment(txn, "ovs-sbctl: %s", args); - - const struct sbrec_sb_global *sb = sbrec_sb_global_first(idl); - if (!sb) { - /* XXX add verification that table is empty */ - sbrec_sb_global_insert(txn); - } - - symtab = ovsdb_symbol_table_create(); - for (c = commands; c < &commands[n_commands]; c++) { - ds_init(&c->output); - c->table = NULL; - } - sbctl_context_init(&sbctl_ctx, NULL, idl, txn, symtab); - for (c = commands; c < &commands[n_commands]; c++) { - sbctl_context_init_command(&sbctl_ctx, c); - if (c->syntax->run) { - (c->syntax->run)(&sbctl_ctx.base); - } - if (sbctl_ctx.base.error) { - ctl_fatal("%s", sbctl_ctx.base.error); - } - sbctl_context_done_command(&sbctl_ctx, c); - - if (sbctl_ctx.base.try_again) { - sbctl_context_done(&sbctl_ctx, NULL); - goto try_again; - } - } - sbctl_context_done(&sbctl_ctx, NULL); - - SHASH_FOR_EACH (node, &symtab->sh) { - struct ovsdb_symbol *symbol = node->data; - if (!symbol->created) { - ctl_fatal("row id \"%s\" is referenced but never created (e.g. " - "with \"-- --id=%s create ...\")", - node->name, node->name); - } - if (!symbol->strong_ref) { - if (!symbol->weak_ref) { - VLOG_WARN("row id \"%s\" was created but no reference to it " - "was inserted, so it will not actually appear in " - "the database", node->name); - } else { - VLOG_WARN("row id \"%s\" was created but only a weak " - "reference to it was inserted, so it will not " - "actually appear in the database", node->name); - } - } - } - - status = ovsdb_idl_txn_commit_block(txn); - if (status == TXN_UNCHANGED || status == TXN_SUCCESS) { - for (c = commands; c < &commands[n_commands]; c++) { - if (c->syntax->postprocess) { - sbctl_context_init(&sbctl_ctx, c, idl, txn, symtab); - (c->syntax->postprocess)(&sbctl_ctx.base); - if (sbctl_ctx.base.error) { - ctl_fatal("%s", sbctl_ctx.base.error); - } - sbctl_context_done(&sbctl_ctx, c); - } - } - } - - switch (status) { - case TXN_UNCOMMITTED: - case TXN_INCOMPLETE: - OVS_NOT_REACHED(); - - case TXN_ABORTED: - /* Should not happen--we never call ovsdb_idl_txn_abort(). */ - ctl_fatal("transaction aborted"); - - case TXN_UNCHANGED: - case TXN_SUCCESS: - break; - - case TXN_TRY_AGAIN: - goto try_again; - - case TXN_ERROR: - ctl_fatal("transaction error: %s", ovsdb_idl_txn_get_error(txn)); - - case TXN_NOT_LOCKED: - /* Should not happen--we never call ovsdb_idl_set_lock(). */ - ctl_fatal("database not locked"); - - default: - OVS_NOT_REACHED(); - } - - ovsdb_symbol_table_destroy(symtab); - - for (c = commands; c < &commands[n_commands]; c++) { - struct ds *ds = &c->output; - - if (c->table) { - table_print(c->table, &table_style); - } else if (oneline) { - size_t j; - - ds_chomp(ds, '\n'); - for (j = 0; j < ds->length; j++) { - int ch = ds->string[j]; - switch (ch) { - case '\n': - fputs("\\n", stdout); - break; - - case '\\': - fputs("\\\\", stdout); - break; - - default: - putchar(ch); - } - } - putchar('\n'); - } else { - fputs(ds_cstr(ds), stdout); - } - ds_destroy(&c->output); - table_destroy(c->table); - free(c->table); - - shash_destroy_free_data(&c->options); - } - free(commands); - ovsdb_idl_txn_destroy(txn); - ovsdb_idl_destroy(idl); - - return true; - -try_again: - /* Our transaction needs to be rerun, or a prerequisite was not met. Free - * resources and return so that the caller can try again. */ - ovsdb_idl_txn_abort(txn); - ovsdb_idl_txn_destroy(txn); - the_idl_txn = NULL; - - ovsdb_symbol_table_destroy(symtab); - for (c = commands; c < &commands[n_commands]; c++) { - ds_destroy(&c->output); - table_destroy(c->table); - free(c->table); - } - return false; -} - -/* Frees the current transaction and the underlying IDL and then calls - * exit(status). - * - * Freeing the transaction and the IDL is not strictly necessary, but it makes - * for a clean memory leak report from valgrind in the normal case. That makes - * it easier to notice real memory leaks. */ -static void -sbctl_exit(int status) -{ - if (the_idl_txn) { - ovsdb_idl_txn_abort(the_idl_txn); - ovsdb_idl_txn_destroy(the_idl_txn); - } - ovsdb_idl_destroy(the_idl); - exit(status); -} - static const struct ctl_command_syntax sbctl_commands[] = { { "init", 0, 0, "", NULL, sbctl_init, NULL, "", RW }, @@ -1850,11 +1408,31 @@ static const struct ctl_command_syntax sbctl_commands[] = { {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO}, }; -/* Registers sbctl and common db commands. */ -static void -sbctl_cmd_init(void) +int +main(int argc, char *argv[]) { - ctl_init(&sbrec_idl_class, sbrec_table_classes, tables, - cmd_show_tables, sbctl_exit); - ctl_register_commands(sbctl_commands); + struct ovn_dbctl_options dbctl_options = { + .db_version = sbrec_get_db_version(), + .default_db = default_sb_db(), + .allow_wait = false, + + .options_env_var_name = "OVN_SBCTL_OPTIONS", + .daemon_env_var_name = "OVN_SB_DAEMON", + + .idl_class = &sbrec_idl_class, + .tables = tables, + .cmd_show_table = cmd_show_tables, + .commands = sbctl_commands, + + .usage = sbctl_usage, + .add_base_prerequisites = sbctl_add_base_prerequisites, + .pre_execute = sbctl_pre_execute, + .post_execute = NULL, + + .ctx_create = sbctl_ctx_create, + .ctx_destroy = sbctl_ctx_destroy, + }; + + return ovn_dbctl_main(argc, argv, &dbctl_options); } + From patchwork Sat Mar 27 00:31:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459069 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6ftQ0qwMz9sCD for ; Sat, 27 Mar 2021 11:32:14 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 4EEE74066D; Sat, 27 Mar 2021 00:32:10 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Ss-TaGuBKT0L; Sat, 27 Mar 2021 00:32:08 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTP id B94014064C; Sat, 27 Mar 2021 00:32:05 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id ACEF0C000D; Sat, 27 Mar 2021 00:32:05 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1E398C000D for ; Sat, 27 Mar 2021 00:32:05 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id C41DB84D89 for ; Sat, 27 Mar 2021 00:32:04 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id befTz6L1ba-H for ; Sat, 27 Mar 2021 00:32:03 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id 517F284D7C for ; Sat, 27 Mar 2021 00:32:03 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id F1920FF804; Sat, 27 Mar 2021 00:32:00 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:30 -0700 Message-Id: <20210327003147.2955790-5-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Ben Pfaff Subject: [ovs-dev] [PATCH ovn 04/21] tests: Miscellaneous debuggability improvements. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Signed-off-by: Ben Pfaff --- tests/ovn.at | 67 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/tests/ovn.at b/tests/ovn.at index 391a8bcd9323..7b6789125ffc 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -9467,9 +9467,10 @@ wait_for_ports_up check ovn-nbctl --wait=hv sync as hv1 ovs-vsctl show -echo "*************************" -ovn-sbctl list DNS -echo "*************************" +ovn-sbctl list DNS > dns +AT_CAPTURE_FILE([dns]) +ovn-sbctl dump-flows > sbflows +AT_CAPTURE_FILE([sbflows]) reset_pcap_file() { local iface=$1 @@ -9582,7 +9583,13 @@ test_dns() { echo $request >> $outport.expected done fi - as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request + if true; then + as hv1 ovs-appctl ofproto/trace br-int in_port=hv1-vif$inport $request > trace$trace + trace=$(expr $trace + 1) + else + as hv1 ovs-appctl dpctl/del-flows + as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request + fi } test_dns6() { @@ -9614,7 +9621,13 @@ test_dns6() { echo $request >> $outport.expected done fi - as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request + if true; then + as hv1 ovs-appctl ofproto/trace br-int in_port=hv1-vif$inport $request > trace$trace + trace=$(expr $trace + 1) + else + as hv1 ovs-appctl dpctl/del-flows + as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request + fi } AT_CAPTURE_FILE([ofctl_monitor0.log]) @@ -9663,8 +9676,7 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Try vm1 again but an all-caps query name - +AS_BOX([Try vm1 again but an all-caps query name]) set_dns_params VM1 src_ip=`ip_to_hex 10 0 0 6` dst_ip=`ip_to_hex 10 0 0 1` @@ -9686,8 +9698,12 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Clear the query name options for ls1-lp2 +AS_BOX([Clear the query name options for ls1-lp2]) ovn-nbctl --wait=hv remove DNS $DNS1 records vm2.ovn.org +ovn-sbctl list DNS > dns2 +AT_CAPTURE_FILE([dns2]) +ovn-sbctl dump-flows > sbflows2 +AT_CAPTURE_FILE([sbflows2]) set_dns_params vm2 src_ip=`ip_to_hex 10 0 0 4` @@ -9706,10 +9722,14 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Clear the query name for ls1-lp1 +AS_BOX([Clear the query name for ls1-lp1]) # Since ls1 has no query names configued, # ovn-northd should not add the DNS flows. ovn-nbctl --wait=hv remove DNS $DNS1 records vm1.ovn.org +ovn-sbctl list DNS > dns3 +AT_CAPTURE_FILE([dns3]) +ovn-sbctl dump-flows > sbflows3 +AT_CAPTURE_FILE([sbflows3]) set_dns_params vm1 src_ip=`ip_to_hex 10 0 0 6` @@ -9728,9 +9748,13 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Test IPv6 (AAAA records) using IPv4 packet. +AS_BOX([Test IPv6 (AAAA records) using IPv4 packet.]) # Add back the DNS options for ls1-lp1. ovn-nbctl --wait=hv set DNS $DNS1 records:vm1.ovn.org="10.0.0.4 aef0::4" +ovn-sbctl list DNS > dns4 +AT_CAPTURE_FILE([dns4]) +ovn-sbctl dump-flows > sbflows4 +AT_CAPTURE_FILE([sbflows4]) set_dns_params vm1_ipv6_only src_ip=`ip_to_hex 10 0 0 6` @@ -9753,7 +9777,7 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Test both IPv4 (A) and IPv6 (AAAA records) using IPv4 packet. +AS_BOX([Test both IPv4 (A) and IPv6 (AAAA records) using IPv4 packet.]) set_dns_params vm1_ipv4_v6 src_ip=`ip_to_hex 10 0 0 6` dst_ip=`ip_to_hex 10 0 0 1` @@ -9775,7 +9799,7 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Invalid type. +AS_BOX([Invalid type]) set_dns_params vm1_invalid_type src_ip=`ip_to_hex 10 0 0 6` dst_ip=`ip_to_hex 10 0 0 1` @@ -9793,7 +9817,7 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Incomplete DNS packet. +AS_BOX([Incomplete DNS packet]) set_dns_params vm1_incomplete src_ip=`ip_to_hex 10 0 0 6` dst_ip=`ip_to_hex 10 0 0 1` @@ -9811,8 +9835,12 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Add one more DNS record to the ls1. +AS_BOX([Add one more DNS record to the ls1]) ovn-nbctl --wait=hv set Logical_switch ls1 dns_records="$DNS1 $DNS2" +ovn-sbctl list DNS > dns5 +AT_CAPTURE_FILE([dns5]) +ovn-sbctl dump-flows > sbflows5 +AT_CAPTURE_FILE([sbflows5]) set_dns_params vm3 src_ip=`ip_to_hex 10 0 0 4` @@ -9835,7 +9863,7 @@ reset_pcap_file hv1-vif2 hv1/vif2 rm -f 1.expected rm -f 2.expected -# Try DNS query over IPv6 +AS_BOX([Try DNS query over IPv6]) set_dns_params vm1 src_ip=aef00000000000000000000000000004 dst_ip=aef00000000000000000000000000001 @@ -10953,10 +10981,10 @@ check ovn-nbctl --wait=hv sync # Check that there is a logical flow in logical switch foo's pipeline # to set the outport to rp-foo with the condition is_chassis_redirect. -ovn-sbctl dump-flows foo > sbflows +OVS_WAIT_UNTIL([ovn-sbctl dump-flows foo > sbflows + test 1 = `grep ls_in_l2_lkup sbflows | \ + grep rp-foo | grep is_chassis_resident | grep priority=50 -c`]) AT_CAPTURE_FILE([sbflows]) -OVS_WAIT_UNTIL([test 1 = `grep ls_in_l2_lkup sbflows | \ -grep rp-foo | grep is_chassis_resident | grep priority=50 -c`]) (echo "---------NB dump-----" ovn-nbctl show @@ -11033,9 +11061,12 @@ options:rxq_pcap=dummy-rx.pcap options:rxq_pcap=${pcap_file}-rx.pcap } +as hv1 ovs-appctl dpif/del-flows + as hv1 reset_pcap_file br-ex_n2 hv1/br-ex_n2 as hv3 reset_pcap_file hv3-vif1 hv3/vif1 as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet +as hv1 ovs-appctl ofproto/trace br-int in_port=hv1-vif1 $packet sleep 2 # On hv1, table 37 check that no packet goes via the tunnel port From patchwork Sat Mar 27 00:31:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459071 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6ftY45MWz9sCD for ; Sat, 27 Mar 2021 11:32:21 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D1C2B60DC6; Sat, 27 Mar 2021 00:32:19 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6qgqfL4jJLnh; Sat, 27 Mar 2021 00:32:17 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTP id 9F43D60DC1; Sat, 27 Mar 2021 00:32:11 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 63058C001C; Sat, 27 Mar 2021 00:32:10 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1E8E4C0015 for ; Sat, 27 Mar 2021 00:32:07 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id D17F040637 for ; Sat, 27 Mar 2021 00:32:06 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id c9fco-w4ohxX for ; Sat, 27 Mar 2021 00:32:05 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp2.osuosl.org (Postfix) with ESMTPS id 1AAD44063E for ; Sat, 27 Mar 2021 00:32:04 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 5DA28FF806; Sat, 27 Mar 2021 00:32:02 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:31 -0700 Message-Id: <20210327003147.2955790-6-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 05/21] ovn-northd-ddlog: Upgrade to ddlog 0.38. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Upcoming commits will use a new --intern-table option of ovsdb2ddlog, so we need to upgrade to the version of ddlog that has that feature. To do so, we need to adapt the code to language changes in ddlog. This commit does that for a change in 0.37 in which, when iterating over a `Group` in a for-loop, the iterator returns `(value, weight)` tuples. This also adapts ovn-northd-ddlog.c to a slightly updated C API. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- NEWS | 2 +- northd/lrouter.dl | 2 +- northd/ovn-northd-ddlog.c | 21 +++++++++++---------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index 5048433148b8..66976c03dc80 100644 --- a/NEWS +++ b/NEWS @@ -5,7 +5,7 @@ Post-v21.03.0 needed for the southbound database when northbound changes occur. It is expected to scale better than the C implementation, for large deployments. (This may take testing and tuning to be effective.) This version of OVN - requires DDLog 0.36. + requires DDLog 0.38. - Introduce ovn-controller incremetal processing engine statistics - ovn-sbctl can now run as a daemon (long-lived, background process). See ovn-sbctl(8) for details. diff --git a/northd/lrouter.dl b/northd/lrouter.dl index 36cedd2dc219..e3afff72f41d 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -382,7 +382,7 @@ LogicalRouterSnatIP(lr, snat_ip, Some{nat}) :- function group_to_setunionmap(g: Group<'K1, ('K2,Set<'V>)>): Map<'K2,Set<'V>> { var map = map_empty(); - for (entry in g) { + for ((entry, _) in g) { (var key, var value) = entry; match (map.get(key)) { None -> map.insert(key, value), diff --git a/northd/ovn-northd-ddlog.c b/northd/ovn-northd-ddlog.c index b7d2c8a5ef8d..0352e40117c8 100644 --- a/northd/ovn-northd-ddlog.c +++ b/northd/ovn-northd-ddlog.c @@ -79,10 +79,11 @@ static table_id WARNING_TABLE_ID; static table_id NB_CFG_TIMESTAMP_ID; /* Initialize frequently used table ids. */ -static void init_table_ids(void) +static void +init_table_ids(ddlog_prog ddlog) { - WARNING_TABLE_ID = ddlog_get_table_id("helpers::Warning"); - NB_CFG_TIMESTAMP_ID = ddlog_get_table_id("NbCfgTimestamp"); + WARNING_TABLE_ID = ddlog_get_table_id(ddlog, "helpers::Warning"); + NB_CFG_TIMESTAMP_ID = ddlog_get_table_id(ddlog, "NbCfgTimestamp"); } struct northd_ctx { @@ -346,7 +347,8 @@ ddlog_clear(struct northd_ctx *ctx) int n_failures = 0; for (int i = 0; ctx->input_relations[i]; i++) { char *table = xasprintf("%s%s", ctx->prefix, ctx->input_relations[i]); - if (ddlog_clear_relation(ctx->ddlog, ddlog_get_table_id(table))) { + if (ddlog_clear_relation(ctx->ddlog, ddlog_get_table_id(ctx->ddlog, + table))) { n_failures++; } free(table); @@ -610,7 +612,7 @@ northd_update_probe_interval(struct northd_ctx *nb, struct northd_ctx *sb) * Any other value is an explicit probe interval request from the * database. */ int probe_interval = 0; - table_id tid = ddlog_get_table_id("Northd_Probe_Interval"); + table_id tid = ddlog_get_table_id(nb->ddlog, "Northd_Probe_Interval"); ddlog_delta *probe_delta = ddlog_delta_remove_table(nb->delta, tid); ddlog_delta_enumerate(probe_delta, northd_update_probe_interval_cb, (uintptr_t) &probe_interval); ddlog_free_delta(probe_delta); @@ -669,7 +671,7 @@ ddlog_table_update_output(struct ds *ds, ddlog_prog ddlog, ddlog_delta *delta, return; } char *table_name = xasprintf("%s::Out_%s", db, table); - ddlog_delta_clear_table(delta, ddlog_get_table_id(table_name)); + ddlog_delta_clear_table(delta, ddlog_get_table_id(ddlog, table_name)); free(table_name); if (!updates[0]) { @@ -947,7 +949,7 @@ get_database_ops(struct northd_ctx *ctx) * We require output-only tables to have an accompanying index * named _Index. */ char *index = xasprintf("%s_Index", table); - index_id idxid = ddlog_get_index_id(index); + index_id idxid = ddlog_get_index_id(ctx->ddlog, index); if (idxid == -1) { VLOG_WARN_RL(&rl, "%s: unknown index", index); free(index); @@ -999,7 +1001,7 @@ get_database_ops(struct northd_ctx *ctx) static int64_t old_sb_cfg_timestamp = INT64_MIN; int64_t new_sb_cfg = old_sb_cfg; if (ctx->has_timestamp_columns) { - table_id sb_cfg_tid = ddlog_get_table_id("SbCfg"); + table_id sb_cfg_tid = ddlog_get_table_id(ctx->ddlog, "SbCfg"); ddlog_delta *sb_cfg_delta = ddlog_delta_remove_table(ctx->delta, sb_cfg_tid); ddlog_delta_enumerate(sb_cfg_delta, northd_update_sb_cfg_cb, @@ -1148,8 +1150,6 @@ main(int argc, char *argv[]) int retval; bool exiting; - init_table_ids(); - fatal_ignore_sigpipe(); ovs_cmdl_proctitle_init(argc, argv); set_program_name(argv[0]); @@ -1179,6 +1179,7 @@ main(int argc, char *argv[]) if (!ddlog) { ovs_fatal(0, "DDlog instance could not be created"); } + init_table_ids(ddlog); unixctl_command_register("enable-cpu-profiling", "", 0, 0, ovn_northd_enable_cpu_profiling, ddlog); From patchwork Sat Mar 27 00:31:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459073 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6ftj5hghz9sCD for ; Sat, 27 Mar 2021 11:32:29 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 2D66A84DD6; Sat, 27 Mar 2021 00:32:27 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6nL_cag7_0_4; Sat, 27 Mar 2021 00:32:24 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTP id 8644784DBC; Sat, 27 Mar 2021 00:32:13 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 310EDC001D; Sat, 27 Mar 2021 00:32:13 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1E6AAC0019 for ; Sat, 27 Mar 2021 00:32:10 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id DA32484DA4 for ; Sat, 27 Mar 2021 00:32:08 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FT5HfrIfY8FJ for ; Sat, 27 Mar 2021 00:32:07 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id B611384D92 for ; Sat, 27 Mar 2021 00:32:06 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 11994FF804; Sat, 27 Mar 2021 00:32:03 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:32 -0700 Message-Id: <20210327003147.2955790-7-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Ben Pfaff , Dumitru Ceara Subject: [ovs-dev] [PATCH ovn 06/21] ovn-northd-ddlog: Preserve NB_Global more carefully. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Dumitru reported in #openvswitch that ovn-northd-ddlog can discard the setting of NB_Global.options:use_logical_dp_groups at startup. I think that this must be because it seems possible that at startup some of the relations in the Out_NB_Global rule aren't populated yet, and yet there is still a row in nb::NB_Global, so that neither rule for Out_NB_Global matches and therefore ovn-northd-ddlog deletes the row. This commit changes the structure of how ovn-northd-ddlog generates Out_NB_Global to ensure that, if there's an input row, it always generates exactly one output row. This should be more robust than the previous version regardless of whether it fixes the exact problem that Dumitru observed (which I did not try to reproduce). Reported-by: Dumitru Ceara Signed-off-by: Ben Pfaff --- northd/ovn_northd.dl | 63 ++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 0063021e13f5..d718425b7de3 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -625,21 +625,25 @@ HvCfgTimestamp(hv_cfg_timestamp) :- not HvCfgTimestamp0(). /* - * NB_Global: - * - set `sb_cfg` to the value of `SB_Global.nb_cfg`. - * - set `hv_cfg` to the smallest value of `nb_cfg` across all `Chassis` - * - FIXME: we use ipsec as unique key to make sure that we don't create multiple `NB_Global` - * instance. There is a potential race condition if this field is modified at the same - * time northd is updating `sb_cfg` or `hv_cfg`. + * nb::Out_NB_Global. + * + * OutNBGlobal0 generates the new record in the common case. + * OutNBGlobal1 generates the new record as a copy of nb::NB_Global, if sb::SB_Global is missing. + * nb::Out_NB_Global makes sure we have only a single record in the relation. + * + * (We don't generate an NB_Global output record if there isn't + * one in the input. We don't have enough entropy available to + * generate a random _uuid. Doesn't seem like a big deal, because + * OVN probably hasn't really been initialized yet.) */ -input relation NbCfgTimestamp[integer] -nb::Out_NB_Global(._uuid = _uuid, - .sb_cfg = sb_cfg, - .hv_cfg = hv_cfg, - .nb_cfg_timestamp = nb_cfg_timestamp, - .hv_cfg_timestamp = hv_cfg_timestamp, - .ipsec = ipsec, - .options = options) :- +relation OutNBGlobal0[nb::Out_NB_Global] +OutNBGlobal0[nb::Out_NB_Global{._uuid = _uuid, + .sb_cfg = sb_cfg, + .hv_cfg = hv_cfg, + .nb_cfg_timestamp = nb_cfg_timestamp, + .hv_cfg_timestamp = hv_cfg_timestamp, + .ipsec = ipsec, + .options = options}] :- NbCfgTimestamp[nb_cfg_timestamp], HvCfgTimestamp(hv_cfg_timestamp), nbg in nb::NB_Global(._uuid = _uuid, .ipsec = ipsec), @@ -654,19 +658,26 @@ nb::Out_NB_Global(._uuid = _uuid, var options2 = options1.insert_imm("max_tunid", "${max_tunid}"), var options = options2.insert_imm("northd_internal_version", ovn_internal_version()). +relation OutNBGlobal1[nb::Out_NB_Global] +OutNBGlobal1[x] :- OutNBGlobal0[x]. +OutNBGlobal1[nb::Out_NB_Global{._uuid = nbg._uuid, + .sb_cfg = nbg.sb_cfg, + .hv_cfg = nbg.hv_cfg, + .ipsec = nbg.ipsec, + .options = nbg.options, + .nb_cfg_timestamp = nbg.nb_cfg_timestamp, + .hv_cfg_timestamp = nbg.hv_cfg_timestamp}] :- + Unit(), + not OutNBGlobal0[_], + nbg in nb::NB_Global(). + +nb::Out_NB_Global[y] :- + OutNBGlobal1[x], + var y = x.group_by(()).group_first(). -/* SB_Global does not exist yet -- just keep the old value of NB_Global */ -nb::Out_NB_Global(._uuid = nbg._uuid, - .sb_cfg = nbg.sb_cfg, - .hv_cfg = nbg.hv_cfg, - .ipsec = nbg.ipsec, - .options = nbg.options, - .nb_cfg_timestamp = nb_cfg_timestamp, - .hv_cfg_timestamp = hv_cfg_timestamp) :- - NbCfgTimestamp[nb_cfg_timestamp], - HvCfgTimestamp(hv_cfg_timestamp), - nbg in nb::NB_Global(), - not sb::SB_Global(). +// Tracks the value that should go into NB_Global's 'nb_cfg_timestamp' column. +// ovn-northd-ddlog.c pushes the current time directly into this relation. +input relation NbCfgTimestamp[integer] output relation SbCfg[integer] SbCfg[sb_cfg] :- nb::Out_NB_Global(.sb_cfg = sb_cfg). From patchwork Sat Mar 27 00:31:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459075 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fv32SRtz9sCD for ; Sat, 27 Mar 2021 11:32:47 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id D765860DBF; Sat, 27 Mar 2021 00:32:44 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vLDocxGwx78U; Sat, 27 Mar 2021 00:32:36 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp3.osuosl.org (Postfix) with ESMTP id 08DC060DFD; Sat, 27 Mar 2021 00:32:27 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id CE128C000B; Sat, 27 Mar 2021 00:32:27 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2361EC000E for ; Sat, 27 Mar 2021 00:32:26 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 9651A84DC8 for ; Sat, 27 Mar 2021 00:32:20 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id nH9QI6vpudhG for ; Sat, 27 Mar 2021 00:32:09 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id 976F284D7C for ; Sat, 27 Mar 2021 00:32:08 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id C3CC4FF803; Sat, 27 Mar 2021 00:32:05 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:33 -0700 Message-Id: <20210327003147.2955790-8-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 07/21] ovn-northd-ddlog: Remove `lr` field from `Router`. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk `relation Router` stores the internal representation of a logical router, consisting of values from the `nb::Logical_Router` table augmented with some additional fields. We used to do this by copying the entire `Logical_Router` record inside `Router`. This proved highly inefficient in scenarios where the set of router ports changes frequently. Every such change modifies the `ports` array inside `Logical_Router`, which triggers an update of the `Router` object, which can cause a bunch of rules to update their outputs. This recomputation is unnecessary as none of these rules look at the `ports` field (`ports` is a slightly backwards way to maintain the relationship between ports and routers by storing the array of ports in the router instead of having each port point to the router). As a workaround, we no longer store the entire `Logical_Router` object in the `Router` table, and instead only copy its relevant fields. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/lrouter.dl | 47 ++++-- northd/ovn_northd.dl | 374 +++++++++++++++++++++---------------------- 2 files changed, 220 insertions(+), 201 deletions(-) diff --git a/northd/lrouter.dl b/northd/lrouter.dl index e3afff72f41d..574926b73b67 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -329,10 +329,10 @@ LogicalRouterNATs(lr, vec_empty()) :- nb::Logical_Router(._uuid = lr), not LogicalRouterNAT(lr, _). -function get_force_snat_ip(lr: nb::Logical_Router, key_type: string): Set = +function get_force_snat_ip(options: Map, key_type: string): Set = { var ips = set_empty(); - match (lr.options.get(key_type ++ "_force_snat_ip")) { + match (options.get(key_type ++ "_force_snat_ip")) { None -> (), Some{s} -> { for (token in s.split(" ")) { @@ -346,8 +346,8 @@ function get_force_snat_ip(lr: nb::Logical_Router, key_type: string): Set, key_type: string): bool { + not get_force_snat_ip(options, key_type).is_empty() } function lb_force_snat_router_ip(lr_options: Map): bool { @@ -355,8 +355,8 @@ function lb_force_snat_router_ip(lr_options: Map): bool { lr_options.contains_key("chassis") } -function force_snat_for_lb(lr: nb::Logical_Router): bool { - not get_force_snat_ip(lr, "lb").is_empty() or lb_force_snat_router_ip(lr.options) +function force_snat_for_lb(lr_options: Map): bool { + not get_force_snat_ip(lr_options, "lb").is_empty() or lb_force_snat_router_ip(lr_options) } /* For each router, collect the set of IPv4 and IPv6 addresses used for SNAT, @@ -370,11 +370,11 @@ function force_snat_for_lb(lr: nb::Logical_Router): bool { relation LogicalRouterSnatIP(lr: uuid, snat_ip: v46_ip, nat: Option) LogicalRouterSnatIP(lr._uuid, force_snat_ip, None) :- lr in nb::Logical_Router(), - var dnat_force_snat_ips = get_force_snat_ip(lr, "dnat"), + var dnat_force_snat_ips = get_force_snat_ip(lr.options, "dnat"), var lb_force_snat_ips = if (lb_force_snat_router_ip(lr.options)) { set_empty() } else { - get_force_snat_ip(lr, "lb") + get_force_snat_ip(lr.options, "lb") }, var force_snat_ip = FlatMap(dnat_force_snat_ips.union(lb_force_snat_ips)). LogicalRouterSnatIP(lr, snat_ip, Some{nat}) :- @@ -418,7 +418,6 @@ LogicalRouterLBs(lr, vec_empty()) :- /* Router relation collects all attributes of a logical router. * - * `lr` - Logical_Router record from the NB database * `l3dgw_port` - optional redirect port (see `DistributedGatewayPort`) * `redirect_port_name` - derived redirect port name (or empty string if * router does not have a redirect port) @@ -432,7 +431,18 @@ LogicalRouterLBs(lr, vec_empty()) :- function chassis_redirect_name(port_name: string): string = "cr-${port_name}" relation &Router( - lr: nb::Logical_Router, + /* Fields copied from nb::Logical_Router. */ + _uuid: uuid, + name: string, + static_routes: Set, + policies: Set, + enabled: Option, + nat: Set, + load_balancer: Set, + options: Map, + external_ids: Map, + + /* Additional computed fields. */ l3dgw_port: Option, redirect_port_name: string, is_gateway: bool, @@ -444,7 +454,16 @@ relation &Router( force_lb_snat: bool, ) -&Router(.lr = lr, +&Router(._uuid = lr._uuid, + .name = lr.name, + .static_routes = lr.static_routes, + .policies = lr.policies, + .enabled = lr.enabled, + .nat = lr.nat, + .load_balancer = lr.load_balancer, + .options = lr.options, + .external_ids = lr.external_ids, + .l3dgw_port = l3dgw_port, .redirect_port_name = match (l3dgw_port) { @@ -576,7 +595,7 @@ relation &RouterPort( nb::Logical_Router_Port[lrp], Some{var networks} = extract_lrp_networks(lrp.mac, lrp.networks), LogicalRouterPort(lrp._uuid, lrouter_uuid), - router in &Router(.lr = nb::Logical_Router{._uuid = lrouter_uuid}), + router in &Router(._uuid = lrouter_uuid), RouterPortIsRedirect(lrp._uuid, is_redirect), RouterPortPeer(lrp._uuid, peer), mcast_cfg in &McastPortCfg(.port = lrp._uuid, .router_port = true), @@ -703,7 +722,7 @@ RouterStaticRoute_(.router = router, .nexthop = route.nexthop, .output_port = route.output_port, .ecmp_symmetric_reply = route.ecmp_symmetric_reply) :- - router in &Router(.lr = nb::Logical_Router{.static_routes = routes}), + router in &Router(.static_routes = routes), var route_id = FlatMap(routes), route in &StaticRoute(.lrsr = nb::Logical_Router_Static_Route{._uuid = route_id}). @@ -724,7 +743,7 @@ RouterStaticRoute(router, key, dsts) :- rsr in RouterStaticRoute_(.router = router, .output_port = None), /* output_port is not specified, find the * router port matching the next hop. */ - port in &RouterPort(.router = &Router{.lr = nb::Logical_Router{._uuid = router.lr._uuid}}, + port in &RouterPort(.router = &Router{._uuid = router._uuid}, .networks = networks), Some{var src_ip} = find_lrp_member_ip(networks, rsr.nexthop), var dst = RouteDst{rsr.nexthop, src_ip, port, rsr.ecmp_symmetric_reply}, diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index d718425b7de3..bb8be08dc55e 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -172,8 +172,8 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, eids }, Some{var router_port} = lsp.options.get("router-port"), - var opt_chassis = peer.and_then(|p| p.router.lr.options.get("chassis")), - var l3dgw_port = peer.and_then(|p| p.router.l3dgw_port), + var opt_chassis = peer.and_then(|p| p.router.options.get("chassis")), + var l3dgw_port = peer.and_then(|p| p.router.l3dgw_port), (var __type, var options) = { var options = ["peer" -> router_port]; match (opt_chassis) { @@ -230,7 +230,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, (rport.lrp.options.get_bool_def("reside-on-redirect-chassis", false) and l3dgw_port.is_some()) or Some{rport.lrp} == l3dgw_port or - (rport.router.lr.options.contains_key("chassis") and + (rport.router.options.contains_key("chassis") and not sw.localnet_ports.is_empty())) { false -> set_empty(), true -> set_singleton(get_garp_nat_addresses(deref(rport))) @@ -246,7 +246,7 @@ OutProxy_Port_Binding(._uuid = lrp._uuid, .gateway_chassis = set_empty(), .ha_chassis_group = None, .options = options, - .datapath = router.lr._uuid, + .datapath = router._uuid, .parent_port = None, .tag = None, // always empty for router ports .mac = set_singleton("${lrp.mac} ${lrp.networks.join(\" \")}"), @@ -254,7 +254,7 @@ OutProxy_Port_Binding(._uuid = lrp._uuid, .external_ids = lrp.external_ids) :- rp in &RouterPort(.lrp = lrp, .router = &router, .peer = peer), RouterPortRAOptionsComplete(lrp._uuid, options0), - (var __type, var options1) = match (router.lr.options.get("chassis")) { + (var __type, var options1) = match (router.options.get("chassis")) { /* TODO: derived ports */ None -> ("patch", map_empty()), Some{lrchassis} -> ("l3gateway", ["l3gateway-chassis" -> lrchassis]) @@ -902,8 +902,8 @@ sb::Out_Multicast_Group (._uuid = hash128((sw.ls._uuid,name)), /* Create a multicast group to flood traffic and reports to router ports with * multicast flood enabled. */ -sb::Out_Multicast_Group (._uuid = hash128((rtr.lr._uuid,name)), - .datapath = rtr.lr._uuid, +sb::Out_Multicast_Group (._uuid = hash128((rtr._uuid,name)), + .datapath = rtr._uuid, .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- @@ -922,7 +922,7 @@ OutProxy_Multicast_Group (.datapath = switch.ls._uuid, /* Create a multicast group for each IGMP group learned by a Router. * 'tunnel_key' == 0 triggers an ID allocation later. */ -OutProxy_Multicast_Group (.datapath = router.lr._uuid, +OutProxy_Multicast_Group (.datapath = router._uuid, .name = address, .ports = port_ids) :- IgmpRouterMulticastGroup(address, &router, port_ids). @@ -4191,7 +4191,7 @@ for (&SwitchPort(.lsp = lsp, .sw = &sw, .peer = Some{&RouterPort{.lrp = lrp, .is_redirect = is_redirect, - .router = &Router{.lr = lr, + .router = &Router{._uuid = lr_uuid, .redirect_port_name = redirect_port_name}}}) if (lsp.addresses.contains("router") and lsp.__type != "external")) { @@ -4229,7 +4229,7 @@ for (&SwitchPort(.lsp = lsp, /* Add ethernet addresses specified in NAT rules on * distributed logical routers. */ if (is_redirect) { - for (LogicalRouterNAT(.lr = lr._uuid, .nat = nat)) { + for (LogicalRouterNAT(.lr = lr_uuid, .nat = nat)) { if (nat.nat.__type == "dnat_and_snat") { Some{var lport} = nat.nat.logical_port in Some{var emac} = nat.nat.external_mac in @@ -4422,10 +4422,10 @@ for (SwitchPortPSAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_nam } /* Logical router ingress table ADMISSION: Admission control framework. */ -for (&Router(.lr = lr)) { +for (&Router(._uuid = lr_uuid)) { /* Logical VLANs not supported. * Broadcast/multicast source address is invalid. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ADMISSION(), .priority = 100, .__match = "vlan.present || eth.src[40]", @@ -4454,7 +4454,7 @@ for (&RouterPort(.lrp = lrp, * the pipeline. */ var actions = "${rEG_INPORT_ETH_ADDR()} = ${lrp_networks.ea}; next;" in { - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ADMISSION(), .priority = 50, .__match = "eth.mcast && inport == ${json_name}", @@ -4468,7 +4468,7 @@ for (&RouterPort(.lrp = lrp, * should only be received on the "redirect-chassis". */ " && is_chassis_resident(${json_string_escape(chassis_redirect_name(lrp.name))})" } else { "" } in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ADMISSION(), .priority = 50, .__match = __match, @@ -4515,11 +4515,11 @@ for (&RouterPort(.lrp = lrp, * */ /* Flows for LOOKUP_NEIGHBOR. */ -for (&Router(.lr = lr, .learn_from_arp_request = learn_from_arp_request)) +for (&Router(._uuid = lr_uuid, .learn_from_arp_request = learn_from_arp_request)) var rLNR = rEGBIT_LOOKUP_NEIGHBOR_RESULT() in var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in { - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LOOKUP_NEIGHBOR(), .priority = 100, .__match = "arp.op == 2", @@ -4528,7 +4528,7 @@ var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in { if (learn_from_arp_request) "" else "${rLNIR} = 1; " } ++ "next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LOOKUP_NEIGHBOR(), .priority = 100, .__match = "nd_na", @@ -4537,7 +4537,7 @@ var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in { if (learn_from_arp_request) "" else "${rLNIR} = 1; " } ++ "next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LOOKUP_NEIGHBOR(), .priority = 100, .__match = "nd_ns", @@ -4550,7 +4550,7 @@ var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in /* For other packet types, we can skip neighbor learning. * So set REGBIT_LOOKUP_NEIGHBOR_RESULT to 1. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LOOKUP_NEIGHBOR(), .priority = 0, .__match = "1", @@ -4559,7 +4559,7 @@ var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in /* Flows for LEARN_NEIGHBOR. */ /* Skip Neighbor learning if not required. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LEARN_NEIGHBOR(), .priority = 100, .__match = @@ -4567,25 +4567,25 @@ var rLNIR = rEGBIT_LOOKUP_NEIGHBOR_IP_RESULT() in { if (learn_from_arp_request) "" else " || ${rLNIR} == 0" }, .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LEARN_NEIGHBOR(), .priority = 90, .__match = "arp", .actions = "put_arp(inport, arp.spa, arp.sha); next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LEARN_NEIGHBOR(), .priority = 90, .__match = "arp", .actions = "put_arp(inport, arp.spa, arp.sha); next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LEARN_NEIGHBOR(), .priority = 90, .__match = "nd_na", .actions = "put_nd(inport, nd.target, nd.tll); next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LEARN_NEIGHBOR(), .priority = 90, .__match = "nd_ns", @@ -4618,7 +4618,7 @@ for (RouterPortNetworksIPv4Addr(rp@&RouterPort{.router = router}, addr)) { var actions = "${rLNR} = lookup_arp(inport, arp.spa, arp.sha); " "${rLNIR} = 1; " "next;" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_LOOKUP_NEIGHBOR(), .priority = 110, .__match = __match.join(" && "), @@ -4630,7 +4630,7 @@ for (RouterPortNetworksIPv4Addr(rp@&RouterPort{.router = router}, addr)) { { if (learn_from_arp_request) "" else "${rLNIR} = lookup_arp_ip(inport, arp.spa); " } ++ "next;" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_LOOKUP_NEIGHBOR(), .priority = 100, .__match = "${match0} && ${match1}", @@ -4641,11 +4641,11 @@ for (RouterPortNetworksIPv4Addr(rp@&RouterPort{.router = router}, addr)) { /* Logical router ingress table IP_INPUT: IP Input. */ -for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { +for (router in &Router(._uuid = lr_uuid, .mcast_cfg = &mcast_cfg)) { /* L3 admission control: drop multicast and broadcast source, localhost * source or destination, and zero network source or destination * (priority 100). */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 100, .__match = "ip4.src_mcast ||" @@ -4662,7 +4662,7 @@ for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { * Drop IPv6 ND packets (priority 85). ND NA packets for router's own * IPs are handled with priority-90 flows. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 85, .__match = "arp || nd", @@ -4672,7 +4672,7 @@ for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { /* Allow IPv6 multicast traffic that's supposed to reach the * router pipeline (e.g., router solicitations). */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 84, .__match = "nd_rs || nd_ra", @@ -4680,7 +4680,7 @@ for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { .external_ids = map_empty()); /* Drop other reserved multicast. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 83, .__match = "ip6.mcast_rsvd", @@ -4689,7 +4689,7 @@ for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { /* Allow other multicast if relay enabled (priority 82). */ var mcast_action = { if (mcast_cfg.relay) { "next;" } else { "drop;" } } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 82, .__match = "ip4.mcast || ip6.mcast", @@ -4698,7 +4698,7 @@ for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { /* Drop Ethernet local broadcast. By definition this traffic should * not be forwarded.*/ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 50, .__match = "eth.bcast", @@ -4707,7 +4707,7 @@ for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { /* TTL discard */ Flow( - .logical_datapath = lr._uuid, + .logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 30, .__match = "ip4 && ip.ttl == {0, 1}", @@ -4716,7 +4716,7 @@ for (router in &Router(.lr = lr, .mcast_cfg = &mcast_cfg)) { /* Pass other traffic not already handled to the next table for * routing. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 0, .__match = "1", @@ -4803,7 +4803,7 @@ for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp) var __match = "ip4.src == " ++ format_v4_networks(networks, true) ++ " && ${rEGBIT_EGRESS_LOOPBACK()} == 0" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 100, .__match = __match, @@ -4818,7 +4818,7 @@ for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp) var __match = "ip4.dst == " ++ format_v4_networks(networks, false) ++ " && icmp4.type == 8 && icmp4.code == 0" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 90, .__match = __match, @@ -4839,7 +4839,7 @@ for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp) * on a regular port, just reply with the port's ETH address. */ LogicalRouterNatArpNdFlow(router, nat) :- - router in &Router(.lr = nb::Logical_Router{._uuid = lr}), + router in &Router(._uuid = lr), LogicalRouterNAT(.lr = lr, .nat = nat@NAT{.nat = &nb::NAT{.__type = __type}}), /* Skip SNAT entries for now, we handle unique SNAT IPs separately * below. @@ -4866,8 +4866,8 @@ LogicalRouterArpNdFlow(router, nat, None, rEG_INPORT_ETH_ADDR(), None, false, 90 * different ETH address. */ LogicalRouterPortNatArpNdFlow(router, nat, l3dgw_port) :- - router in &Router(.lr = lr, .l3dgw_port = Some{l3dgw_port}), - LogicalRouterNAT(lr._uuid, nat), + router in &Router(._uuid = lr_uuid, .l3dgw_port = Some{l3dgw_port}), + LogicalRouterNAT(lr_uuid, nat), /* Skip SNAT entries for now, we handle unique SNAT IPs separately * below. */ @@ -4938,7 +4938,7 @@ relation LogicalRouterArpFlow( drop: bool, priority: integer, external_ids: Map) -Flow(.logical_datapath = lr.lr._uuid, +Flow(.logical_datapath = lr._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = priority, .__match = __match, @@ -4983,7 +4983,7 @@ relation LogicalRouterNdFlow( drop: bool, priority: integer, external_ids: Map) -Flow(.logical_datapath = lr.lr._uuid, +Flow(.logical_datapath = lr._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = priority, .__match = __match, @@ -5028,7 +5028,7 @@ for (RouterPortNetworksIPv4Addr(.port = &RouterPort{.lrp = lrp, .is_redirect = is_redirect}, .addr = addr)) { - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 40, .__match = "inport == ${json_name} && ip4 && " @@ -5063,7 +5063,7 @@ for (RouterPortNetworksIPv4Addr(.port = &RouterPort{.lrp = lrp, } for (&RouterPort(.lrp = lrp, - .router = router@&Router{.lr = lr}, + .router = router@&Router{._uuid = lr_uuid}, .json_name = json_name, .networks = networks, .is_redirect = is_redirect)) @@ -5071,7 +5071,7 @@ var residence_check = match (is_redirect) { true -> Some{"is_chassis_resident(${router.redirect_port_name})"}, false -> None } in { - for (RouterLBVIP(.router = &Router{.lr = nb::Logical_Router{._uuid= lr._uuid}}, .vip = vip)) { + for (RouterLBVIP(.router = &Router{._uuid= lr_uuid}, .vip = vip)) { Some{(var ip_address, _)} = ip_address_and_port_from_lb_key(vip) in { IPv4{var ipv4} = ip_address in LogicalRouterArpFlow(.lr = router, @@ -5113,7 +5113,7 @@ Flow(.logical_datapath = lr_uuid, &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid}, .router = &Router{.snat_ips = snat_ips, .force_lb_snat = false, - .lr = nb::Logical_Router{._uuid = lr_uuid}}, + ._uuid = lr_uuid}, .networks = networks), var addr = FlatMap(networks.ipv4_addrs), not snat_ips.contains_key(IPv4{addr.addr}), @@ -5127,7 +5127,7 @@ Flow(.logical_datapath = lr_uuid, &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid}, .router = &Router{.snat_ips = snat_ips, .force_lb_snat = false, - .lr = nb::Logical_Router{._uuid = lr_uuid}}, + ._uuid = lr_uuid}, .networks = networks), var addr = FlatMap(networks.ipv6_addrs), not snat_ips.contains_key(IPv6{addr.addr}), @@ -5135,7 +5135,7 @@ Flow(.logical_datapath = lr_uuid, for (RouterPortNetworksIPv4Addr( .port = &RouterPort{ - .router = &Router{.lr = lr, + .router = &Router{._uuid = lr_uuid, .l3dgw_port = None, .is_gateway = false}, .lrp = lrp}, @@ -5143,7 +5143,7 @@ for (RouterPortNetworksIPv4Addr( { /* UDP/TCP/SCTP port unreachable. */ var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag && udp" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 80, .__match = __match, @@ -5157,7 +5157,7 @@ for (RouterPortNetworksIPv4Addr( .external_ids = stage_hint(lrp._uuid)); var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag && tcp" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 80, .__match = __match, @@ -5168,7 +5168,7 @@ for (RouterPortNetworksIPv4Addr( .external_ids = stage_hint(lrp._uuid)); var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag && sctp" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 80, .__match = __match, @@ -5179,7 +5179,7 @@ for (RouterPortNetworksIPv4Addr( .external_ids = stage_hint(lrp._uuid)); var __match = "ip4 && ip4.dst == ${addr.addr} && !ip.later_frag" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 70, .__match = __match, @@ -5194,7 +5194,7 @@ for (RouterPortNetworksIPv4Addr( } /* DHCPv6 reply handling */ -Flow(.logical_datapath = rp.router.lr._uuid, +Flow(.logical_datapath = rp.router._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 100, .__match = "ip6.dst == ${ipv6_addr.addr} " @@ -5219,7 +5219,7 @@ for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp) var __match = "ip6.dst == " ++ format_v6_networks(networks) ++ " && icmp6.type == 128 && icmp6.code == 0" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 90, .__match = __match, @@ -5262,7 +5262,7 @@ for (RouterPortNetworksIPv6Addr(.port = &RouterPort{.lrp = lrp, /* UDP/TCP/SCTP port unreachable */ for (RouterPortNetworksIPv6Addr( - .port = &RouterPort{.router = &Router{.lr = lr, + .port = &RouterPort{.router = &Router{._uuid = lr_uuid, .l3dgw_port = None, .is_gateway = false}, .lrp = lrp, @@ -5270,7 +5270,7 @@ for (RouterPortNetworksIPv6Addr( .addr = addr)) { var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag && tcp" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 80, .__match = __match, @@ -5281,7 +5281,7 @@ for (RouterPortNetworksIPv6Addr( .external_ids = stage_hint(lrp._uuid)); var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag && sctp" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 80, .__match = __match, @@ -5292,7 +5292,7 @@ for (RouterPortNetworksIPv6Addr( .external_ids = stage_hint(lrp._uuid)); var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag && udp" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 80, .__match = __match, @@ -5306,7 +5306,7 @@ for (RouterPortNetworksIPv6Addr( .external_ids = stage_hint(lrp._uuid)); var __match = "ip6 && ip6.dst == ${addr.addr} && !ip.later_frag" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 70, .__match = __match, @@ -5339,7 +5339,7 @@ for (RouterPortNetworksIPv6Addr(.port = &RouterPort{.router = &router, "icmp6.type = 3; /* Time exceeded */ " "icmp6.code = 0; /* TTL exceeded in transit */ " "next; };" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 40, .__match = __match, @@ -5357,20 +5357,20 @@ function default_allow_flow(datapath: uuid, stage: Stage): Flow { .actions = "next;", .external_ids = map_empty()} } -for (&Router(.lr = lr)) { +for (&Router(._uuid = lr_uuid)) { /* Packets are allowed by default. */ - Flow[default_allow_flow(lr._uuid, s_ROUTER_IN_DEFRAG())]; - Flow[default_allow_flow(lr._uuid, s_ROUTER_IN_UNSNAT())]; - Flow[default_allow_flow(lr._uuid, s_ROUTER_OUT_SNAT())]; - Flow[default_allow_flow(lr._uuid, s_ROUTER_IN_DNAT())]; - Flow[default_allow_flow(lr._uuid, s_ROUTER_OUT_UNDNAT())]; - Flow[default_allow_flow(lr._uuid, s_ROUTER_OUT_EGR_LOOP())]; - Flow[default_allow_flow(lr._uuid, s_ROUTER_IN_ECMP_STATEFUL())]; + Flow[default_allow_flow(lr_uuid, s_ROUTER_IN_DEFRAG())]; + Flow[default_allow_flow(lr_uuid, s_ROUTER_IN_UNSNAT())]; + Flow[default_allow_flow(lr_uuid, s_ROUTER_OUT_SNAT())]; + Flow[default_allow_flow(lr_uuid, s_ROUTER_IN_DNAT())]; + Flow[default_allow_flow(lr_uuid, s_ROUTER_OUT_UNDNAT())]; + Flow[default_allow_flow(lr_uuid, s_ROUTER_OUT_EGR_LOOP())]; + Flow[default_allow_flow(lr_uuid, s_ROUTER_IN_ECMP_STATEFUL())]; /* Send the IPv6 NS packets to next table. When ovn-controller * generates IPv6 NS (for the action - nd_ns{}), the injected * packet would go through conntrack - which is not required. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_SNAT(), .priority = 120, .__match = "nd_ns", @@ -5433,7 +5433,7 @@ function lrouter_nat_add_ext_ip_match( }; ("", - Some{Flow{.logical_datapath = router.lr._uuid, + Some{Flow{.logical_datapath = router._uuid, .stage = if (is_src) { s_ROUTER_IN_DNAT() } else { s_ROUTER_OUT_SNAT() }, .priority = priority, .__match = "${__match} && ${ipX}.${dir} == $${__as.name}", @@ -5471,17 +5471,17 @@ Flow(.logical_datapath = logical_router, /* Higher priority rules to force SNAT with the router port ip. * This only takes effect when the packet has already been * load balanced once. */ -for (rp in &RouterPort(.router = &Router{.lr = lr}, .lrp = lrp)) { - if (lb_force_snat_router_ip(lr.options) and rp.peer != PeerNone) { +for (rp in &RouterPort(.router = &Router{._uuid = lr_uuid, .options = lr_options}, .lrp = lrp)) { + if (lb_force_snat_router_ip(lr_options) and rp.peer != PeerNone) { Some{var ipv4} = rp.networks.ipv4_addrs.nth(0) in { - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_UNSNAT(), .priority = 110, .__match = "inport == ${rp.json_name} && ip4.dst == ${ipv4.addr}", .actions = "ct_snat;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_SNAT(), .priority = 110, .__match = "flags.force_snat_for_lb == 1 && ip4 && outport == ${rp.json_name}", @@ -5499,14 +5499,14 @@ for (rp in &RouterPort(.router = &Router{.lr = lr}, .lrp = lrp)) { * last in the list. So add the flows only if n_ipv6_addrs > 1. */ if (rp.networks.ipv6_addrs.len() > 1) { Some{var ipv6} = rp.networks.ipv6_addrs.nth(0) in { - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_UNSNAT(), .priority = 110, .__match = "inport == ${rp.json_name} && ip6.dst == ${ipv6.addr}", .actions = "ct_snat;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_SNAT(), .priority = 110, .__match = "flags.force_snat_for_lb == 1 && ip6 && outport == ${rp.json_name}", @@ -5526,13 +5526,13 @@ for (rp in &RouterPort(.router = &Router{.lr = lr}, .lrp = lrp)) { /* NAT rules are only valid on Gateway routers and routers with * l3dgw_port (router has a port with "redirect-chassis" * specified). */ -for (r in &Router(.lr = lr, +for (r in &Router(._uuid = lr_uuid, .l3dgw_port = l3dgw_port, .redirect_port_name = redirect_port_name, .is_gateway = is_gateway) if l3dgw_port.is_some() or is_gateway) { - for (LogicalRouterNAT(.lr = lr._uuid, .nat = nat)) { + for (LogicalRouterNAT(.lr = lr_uuid, .nat = nat)) { var ipX = nat.external_ip.ipX() in var xx = nat.external_ip.xxreg() in /* Check the validity of nat->logical_ip. 'logical_ip' can @@ -5541,7 +5541,7 @@ for (r in &Router(.lr = lr, true == match ((mask.is_all_ones(), nat.nat.__type)) { (_, "snat") -> true, (false, _) -> { - warn("bad ip ${nat.nat.logical_ip} for dnat in router ${uuid2str(lr._uuid)}"); + warn("bad ip ${nat.nat.logical_ip} for dnat in router ${uuid2str(lr_uuid)}"); false }, _ -> true @@ -5573,7 +5573,7 @@ for (r in &Router(.lr = lr, } else { "ct_snat;" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_UNSNAT(), .priority = 90, .__match = "ip && ${ipX}.dst == ${nat.nat.external_ip}", @@ -5597,7 +5597,7 @@ for (r in &Router(.lr = lr, } else { "ct_snat;" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_UNSNAT(), .priority = 100, .__match = __match, @@ -5628,7 +5628,7 @@ for (r in &Router(.lr = lr, Some{var f} = ext_flow in Flow[f]; var flag_action = - if (has_force_snat_ip(lr, "dnat")) { + if (has_force_snat_ip(r.options, "dnat")) { /* Indicate to the future tables that a DNAT has taken * place and a force SNAT needs to be done in the * Egress SNAT table. */ @@ -5640,7 +5640,7 @@ for (r in &Router(.lr = lr, "flags.loopback = 1; " "ct_dnat(${ip_and_ports});" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_DNAT(), .priority = 100, .__match = __match ++ ext_ip_match, @@ -5669,7 +5669,7 @@ for (r in &Router(.lr = lr, } else { "ct_dnat(${ip_and_ports});" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_DNAT(), .priority = 100, .__match = __match ++ ext_ip_match, @@ -5684,7 +5684,7 @@ for (r in &Router(.lr = lr, if (nat.nat.__type == "snat") { var __match = "inport == ${gwport_name} && " "${ipX}.src == ${nat.nat.external_ip}" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_IP_INPUT(), .priority = 120, .__match = __match, @@ -5699,7 +5699,7 @@ for (r in &Router(.lr = lr, Some{value} -> "${value}", None -> gwport.mac } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = __match, @@ -5736,7 +5736,7 @@ for (r in &Router(.lr = lr, } else { "ct_dnat;" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_UNDNAT(), .priority = 100, .__match = __match, @@ -5771,7 +5771,7 @@ for (r in &Router(.lr = lr, "ct_snat(${ip_and_ports});" } in Some{var plen} = mask.cidr_bits() in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_SNAT(), .priority = plen as bit<64> + 1, .__match = __match ++ ext_ip_match, @@ -5809,7 +5809,7 @@ for (r in &Router(.lr = lr, Some{var plen} = mask.cidr_bits() in var priority = (plen as bit<64>) + 1 in var centralized_boost = if (mac == None) 128 else 0 in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_SNAT(), .priority = priority + centralized_boost, .__match = __match ++ ext_ip_match, @@ -5834,7 +5834,7 @@ for (r in &Router(.lr = lr, * down in the pipeline. */ var actions = "${rEG_INPORT_ETH_ADDR()} = ${gwport.mac}; next;" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ADMISSION(), .priority = 50, .__match = __match, @@ -5861,7 +5861,7 @@ for (r in &Router(.lr = lr, "eth.src = ${external_mac}; " "${xx}${rEG_SRC()} = ${nat.nat.external_ip}; " "next;" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_GW_REDIRECT(), .priority = 100, .__match = __match, @@ -5897,7 +5897,7 @@ for (r in &Router(.lr = lr, regs.join("") ++ "${rEGBIT_EGRESS_LOOPBACK()} = 1; " "next(pipeline=ingress, table=0); };" in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_EGR_LOOP(), .priority = 100, .__match = __match, @@ -5908,15 +5908,15 @@ for (r in &Router(.lr = lr, /* Handle force SNAT options set in the gateway router. */ if (l3dgw_port == None) { - var dnat_force_snat_ips = get_force_snat_ip(lr, "dnat") in + var dnat_force_snat_ips = get_force_snat_ip(r.options, "dnat") in if (not dnat_force_snat_ips.is_empty()) - LogicalRouterForceSnatFlows(.logical_router = lr._uuid, + LogicalRouterForceSnatFlows(.logical_router = lr_uuid, .ips = dnat_force_snat_ips, .context = "dnat"); - var lb_force_snat_ips = get_force_snat_ip(lr, "lb") in + var lb_force_snat_ips = get_force_snat_ip(r.options, "lb") in if (not lb_force_snat_ips.is_empty()) - LogicalRouterForceSnatFlows(.logical_router = lr._uuid, + LogicalRouterForceSnatFlows(.logical_router = lr_uuid, .ips = lb_force_snat_ips, .context = "lb"); @@ -5929,7 +5929,7 @@ for (r in &Router(.lr = lr, * does not have any feature that depends on the source * ip address being external IP address for IP routing, * we can do it here, saving a future re-circulation. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_DNAT(), .priority = 50, .__match = "ip", @@ -5950,11 +5950,11 @@ function nats_contain_vip(nats: Vec, vip: v46_ip): bool { /* Load balancing and packet defrag are only valid on * Gateway routers or router with gateway port. */ for (RouterLBVIP( - .router = &Router{.lr = lr, - .l3dgw_port = l3dgw_port, - .redirect_port_name = redirect_port_name, - .is_gateway = is_gateway, - .nats = nats}, + .router = r@&Router{._uuid = lr_uuid, + .l3dgw_port = l3dgw_port, + .redirect_port_name = redirect_port_name, + .is_gateway = is_gateway, + .nats = nats}, .lb = lb, .vip = vip, .backends = backends) @@ -5965,7 +5965,7 @@ for (RouterLBVIP( for (HasEventElbMeter(has_elb_meter)) { Some {(var __match, var __action)} = build_empty_lb_event_flow(vip, lb, has_elb_meter) in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_DNAT(), .priority = 130, .__match = __match, @@ -5997,7 +5997,7 @@ for (RouterLBVIP( * We create one for each VIP:port pair; flows with the same IP and * different port numbers will produce identical flows that will * get merged by DDlog. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_DEFRAG(), .priority = 100, .__match = __match, @@ -6021,16 +6021,16 @@ for (RouterLBVIP( (Some{gwport}, true) -> " && is_chassis_resident(${redirect_port_name})", _ -> "" } in - var force_snat_for_lb = force_snat_for_lb(lr) in + var has_force_snat_ip = force_snat_for_lb(r.options) in { /* A match and actions for established connections. */ var est_match = "ct.est && " ++ __match in var actions = - match (force_snat_for_lb) { + match (has_force_snat_ip) { true -> "flags.force_snat_for_lb = 1; ct_dnat;", false -> "ct_dnat;" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_DNAT(), .priority = prio, .__match = est_match, @@ -6052,7 +6052,7 @@ for (RouterLBVIP( var match3 = "${ipX} && ${ipX}.dst == ${ip_address} && ${proto}" ++ if (port != 0) { " && ${proto}.dst == ${port}" } else { "" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_UNSNAT(), .priority = 120, .__match = match3, @@ -6087,11 +6087,11 @@ for (RouterLBVIP( ") && outport == ${json_string_escape(gwport.name)} && " "is_chassis_resident(${redirect_port_name})" in var action = - match (force_snat_for_lb) { + match (has_force_snat_ip) { true -> "flags.force_snat_for_lb = 1; ct_dnat;", false -> "ct_dnat;" } in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_UNDNAT(), .priority = 120, .__match = undnat_match, @@ -6106,7 +6106,7 @@ for (RouterLBVIP( * via add_router_lb_flow(). One flow is for specific matching * on ct.new with an action of "ct_lb($targets);". The other * flow is for ct.est with an action of "ct_dnat;". */ -Flow(.logical_datapath = r.lr._uuid, +Flow(.logical_datapath = r._uuid, .stage = s_ROUTER_IN_DNAT(), .priority = priority, .__match = __match, @@ -6115,7 +6115,7 @@ Flow(.logical_datapath = r.lr._uuid, r in &Router(), r.l3dgw_port.is_some() or r.is_gateway, LBVIPWithStatus[lbvip@&LBVIPWithStatus{.lb = lb}], - r.lr.load_balancer.contains(lb._uuid), + r.load_balancer.contains(lb._uuid), var __match = "ct.new && " ++ get_match_for_lb_key(lbvip.vip_addr, lbvip.vip_port, lb.protocol, true) ++ @@ -6124,7 +6124,7 @@ Flow(.logical_datapath = r.lr._uuid, _ -> "" }, var priority = if (lbvip.vip_port != 0) 120 else 110, - var force_snat = if (force_snat_for_lb(r.lr)) "flags.force_snat_for_lb = 1; " else "", + var force_snat = if (force_snat_for_lb(r.options)) "flags.force_snat_for_lb = 1; " else "", var actions = build_lb_vip_actions(lbvip, s_ROUTER_OUT_SNAT(), force_snat). @@ -6266,7 +6266,7 @@ for (&RouterPort[port@RouterPort{.lrp = lrp@nb::Logical_Router_Port{.peer = None Some{prf} -> ", router_preference = \"${prf}\"" } in var actions = actions0 ++ router_preference ++ prefix ++ "); next;" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ND_RA_OPTIONS(), .priority = 50, .__match = __match, @@ -6280,7 +6280,7 @@ for (&RouterPort[port@RouterPort{.lrp = lrp@nb::Logical_Router_Port{.peer = None "ip6.dst = ip6.src; ip6.src = ${ip6_str}; " "outport = inport; flags.loopback = 1; " "output;" in - Flow(.logical_datapath = router.lr._uuid, + Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ND_RA_RESPONSE(), .priority = 50, .__match = __match, @@ -6293,15 +6293,15 @@ for (&RouterPort[port@RouterPort{.lrp = lrp@nb::Logical_Router_Port{.peer = None /* Logical router ingress table ND_RA_OPTIONS, ND_RA_RESPONSE: RS responder, by * default goto next. (priority 0)*/ -for (&Router(.lr = lr)) +for (&Router(._uuid = lr_uuid)) { - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ND_RA_OPTIONS(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ND_RA_RESPONSE(), .priority = 0, .__match = "1", @@ -6363,7 +6363,7 @@ for (Route(.port = port, "flags.loopback = 1; " "next;" in { - Flow(.logical_datapath = port.router.lr._uuid, + Flow(.logical_datapath = port.router._uuid, .stage = s_ROUTER_IN_IP_ROUTING(), .priority = priority as integer, .__match = __match, @@ -6371,7 +6371,7 @@ for (Route(.port = port, .external_ids = stage_hint(port.lrp._uuid)); if (port.has_bfd) { - Flow(.logical_datapath = port.router.lr._uuid, + Flow(.logical_datapath = port.router._uuid, .stage = s_ROUTER_IN_IP_ROUTING(), .priority = priority as integer + 1, .__match = "${__match} && udp.dst == 3784", @@ -6406,7 +6406,7 @@ Route(key, port, src_ip, None) :- var key = RouteKey{DstIp, IPv6{addr.addr}, addr.plen}, var src_ip = IPv6{addr.addr}. -Flow(.logical_datapath = r.lr._uuid, +Flow(.logical_datapath = r._uuid, .stage = s_ROUTER_IN_IP_ROUTING_ECMP(), .priority = 150, .__match = "${rEG_ECMP_GROUP_ID()} == 0", @@ -6448,7 +6448,7 @@ EcmpGroup(group_id, router, key, dsts, route_match, route_priority) :- (var route_match, var route_priority0) = build_route_match(key), var route_priority = route_priority0 as integer. -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_ROUTING(), .priority = route_priority, .__match = route_match, @@ -6468,7 +6468,7 @@ Flow(.logical_datapath = router.lr._uuid, "${rEG_ECMP_GROUP_ID()} = ${group_id}; " /* XXX */ "${rEG_ECMP_MEMBER_ID()} = select(${all_member_ids});". -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_ROUTING_ECMP(), .priority = 100, .__match = __match, @@ -6501,7 +6501,7 @@ EcmpSymmetricReply(router, dst, route_match, tunkey) :- dst.ecmp_symmetric_reply, PortTunKeyAllocation(.port = dst.port.lrp._uuid, .tunkey = tunkey). -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_DEFRAG(), .priority = 100, .__match = __match, @@ -6516,7 +6516,7 @@ Flow(.logical_datapath = router.lr._uuid, /* Save src eth and inport in ct_label for packets that arrive over * an ECMP route. */ -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ECMP_STATEFUL(), .priority = 100, .__match = __match, @@ -6531,7 +6531,7 @@ Flow(.logical_datapath = router.lr._uuid, /* Bypass ECMP selection if we already have ct_label information * for where to route the packet. */ -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_ROUTING(), .priority = 100, .__match = "${ecmp_reply} && ${route_match}", @@ -6543,13 +6543,13 @@ Flow(.logical_datapath = router.lr._uuid, "next;", .external_ids = map_empty()), /* Egress reply traffic for symmetric ECMP routes skips router policies. */ -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_POLICY(), .priority = 65535, .__match = ecmp_reply, .actions = "next;", .external_ids = map_empty()), -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 200, .__match = ecmp_reply, @@ -6566,7 +6566,7 @@ Flow(.logical_datapath = router.lr._uuid, /* Drop IPv6 multicast traffic that shouldn't be forwarded, * i.e., router solicitation and router advertisement. */ -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_IP_ROUTING(), .priority = 550, .__match = "nd_rs || nd_ra", @@ -6591,7 +6591,7 @@ for (IgmpRouterMulticastGroup(address, &rtr, ports)) { } in Some{var ip} = ip46_parse(address) in var ipX = ip.ipX() in - UniqueFlow[Flow{.logical_datapath = rtr.lr._uuid, + UniqueFlow[Flow{.logical_datapath = rtr._uuid, .stage = s_ROUTER_IN_IP_ROUTING(), .priority = 500, .__match = "${ipX} && ${ipX}.dst == ${address} ", @@ -6617,7 +6617,7 @@ for (RouterMcastFloodPorts(&rtr, flood_ports) if rtr.mcast_cfg.relay) { } else { "drop;" } in - AnnotatedFlow(.f = Flow{.logical_datapath = rtr.lr._uuid, + AnnotatedFlow(.f = Flow{.logical_datapath = rtr._uuid, .stage = s_ROUTER_IN_IP_ROUTING(), .priority = 450, .__match = "ip4.mcast || ip6.mcast", @@ -6635,17 +6635,17 @@ for (RouterMcastFloodPorts(&rtr, flood_ports) if rtr.mcast_cfg.relay) { * the appropriate register to the next-hop IP address (leaving * 'ip[46].dst', the packet’s final destination, unchanged), and * advances to the next table for ARP/ND resolution. */ -for (&Router(.lr = lr)) { +for (&Router(._uuid = lr_uuid)) { /* This is a catch-all rule. It has the lowest priority (0) * does a match-all("1") and pass-through (next) */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_POLICY(), .priority = 0, .__match = "1", .actions = "${rEG_ECMP_GROUP_ID()} = 0; next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_POLICY_ECMP(), .priority = 150, .__match = "${rEG_ECMP_GROUP_ID()} == 0", @@ -6667,14 +6667,14 @@ function pkt_mark_policy(options: Map): string { "" } } -Flow(.logical_datapath = r.lr._uuid, +Flow(.logical_datapath = r._uuid, .stage = s_ROUTER_IN_POLICY(), .priority = policy.priority, .__match = policy.__match, .actions = actions, .external_ids = stage_hint(policy._uuid)) :- r in &Router(), - var policy_uuid = FlatMap(r.lr.policies), + var policy_uuid = FlatMap(r.policies), policy in nb::Logical_Router_Policy(._uuid = policy_uuid), policy.action == "reroute", Some{var nexthop_s} = match (policy.nexthops.size()) { @@ -6718,7 +6718,7 @@ relation EcmpReroutePolicy( ) EcmpReroutePolicy(r, policy, ecmp_group_id) :- r in &Router(), - var policy_uuid = FlatMap(r.lr.policies), + var policy_uuid = FlatMap(r.policies), policy in nb::Logical_Router_Policy(._uuid = policy_uuid), policy.action == "reroute", policy.nexthops.size() > 1, @@ -6728,7 +6728,7 @@ EcmpReroutePolicy(r, policy, ecmp_group_id) :- var pair = FlatMap(numbered_policies), (var policy, var ecmp_group_id) = pair, all_same_addr_family(policy.nexthops). -Flow(.logical_datapath = r.lr._uuid, +Flow(.logical_datapath = r._uuid, .stage = s_ROUTER_IN_POLICY_ECMP(), .priority = 100, .__match = __match, @@ -6752,7 +6752,7 @@ Flow(.logical_datapath = r.lr._uuid, "next;"), var __match = ("${rEG_ECMP_GROUP_ID()} == ${ecmp_group_id} && " "${rEG_ECMP_MEMBER_ID()} == ${member_id}"). -Flow(.logical_datapath = r.lr._uuid, +Flow(.logical_datapath = r._uuid, .stage = s_ROUTER_IN_POLICY(), .priority = policy.priority, .__match = policy.__match, @@ -6769,25 +6769,25 @@ Flow(.logical_datapath = r.lr._uuid, }, var actions = ("${rEG_ECMP_GROUP_ID()} = ${ecmp_group_id}; " "${rEG_ECMP_MEMBER_ID()} = select(${member_ids});"). - -Flow(.logical_datapath = r.lr._uuid, + +Flow(.logical_datapath = r._uuid, .stage = s_ROUTER_IN_POLICY(), .priority = policy.priority, .__match = policy.__match, .actions = "drop;", .external_ids = stage_hint(policy._uuid)) :- r in &Router(), - var policy_uuid = FlatMap(r.lr.policies), + var policy_uuid = FlatMap(r.policies), policy in nb::Logical_Router_Policy(._uuid = policy_uuid), policy.action == "drop". -Flow(.logical_datapath = r.lr._uuid, +Flow(.logical_datapath = r._uuid, .stage = s_ROUTER_IN_POLICY(), .priority = policy.priority, .__match = policy.__match, .actions = pkt_mark_policy(policy.options) ++ "${rEG_ECMP_GROUP_ID()} = 0; next;", .external_ids = stage_hint(policy._uuid)) :- r in &Router(), - var policy_uuid = FlatMap(r.lr.policies), + var policy_uuid = FlatMap(r.policies), policy in nb::Logical_Router_Policy(._uuid = policy_uuid), policy.action == "allow". @@ -6799,8 +6799,8 @@ Flow(.logical_datapath = r.lr._uuid, * Multicast packets already have the outport set so just advance to next * table (priority 500). */ -for (&Router(.lr = lr)) { - Flow(.logical_datapath = lr._uuid, +for (&Router(._uuid = lr_uuid)) { + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 500, .__match = "ip4.mcast || ip6.mcast", @@ -6835,7 +6835,7 @@ for (rp in &RouterPort(.peer = PeerRouter{peer_port, _}, var __match = "outport == ${peer_json_name} && " "${rEG_NEXT_HOP()} == " ++ format_v4_networks(networks, false) in - Flow(.logical_datapath = peer_router.lr._uuid, + Flow(.logical_datapath = peer_router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = __match, @@ -6847,7 +6847,7 @@ for (rp in &RouterPort(.peer = PeerRouter{peer_port, _}, var __match = "outport == ${peer_json_name} && " "xx${rEG_NEXT_HOP()} == " ++ format_v6_networks(networks) in - Flow(.logical_datapath = peer_router.lr._uuid, + Flow(.logical_datapath = peer_router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = __match, @@ -6863,7 +6863,7 @@ for (rp in &RouterPort(.peer = PeerRouter{peer_port, _}, * is "bridged", instead of calling "get_arp" * on this node, we will redirect the packet to gateway * chassis, by setting destination mac router port mac.*/ -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 50, .__match = "outport == ${rp.json_name} && " @@ -6889,7 +6889,7 @@ Flow(.logical_datapath = lr_uuid, .external_ids = stage_hint(lrp_uuid)) :- &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid}, .router = &Router{.snat_ips = snat_ips, - .lr = nb::Logical_Router{._uuid = lr_uuid}}, + ._uuid = lr_uuid}, .networks = networks), var addr = FlatMap(networks.ipv4_addrs), snat_ips.contains_key(IPv4{addr.addr}), @@ -6902,7 +6902,7 @@ Flow(.logical_datapath = lr_uuid, .external_ids = stage_hint(lrp_uuid)) :- &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid}, .router = &Router{.snat_ips = snat_ips, - .lr = nb::Logical_Router{._uuid = lr_uuid}}, + ._uuid = lr_uuid}, .networks = networks), var addr = FlatMap(networks.ipv6_addrs), snat_ips.contains_key(IPv6{addr.addr}), @@ -6923,7 +6923,7 @@ for (SwitchPortIPv4Address( .peer = Some{&peer@RouterPort{.router = &peer_router}})) { Some{_} = find_lrp_member_ip(peer.networks, IPv4{addr.addr}) in - Flow(.logical_datapath = peer_router.lr._uuid, + Flow(.logical_datapath = peer_router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = "outport == ${peer.json_name} && " @@ -6943,7 +6943,7 @@ for (SwitchPortIPv6Address( .peer = Some{&peer@RouterPort{.router = &peer_router}})) { Some{_} = find_lrp_member_ip(peer.networks, IPv6{addr.addr}) in - Flow(.logical_datapath = peer_router.lr._uuid, + Flow(.logical_datapath = peer_router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = "outport == ${peer.json_name} && " @@ -6973,7 +6973,7 @@ function is_empty_set_or_string(s: Option): bool = { * 00:00:00:00:00:00 and advance to next table so that ARP is * resolved by router pipeline using the arp{} action. * The MAC_Binding entry for the virtual ip might be invalid. */ -Flow(.logical_datapath = peer.router.lr._uuid, +Flow(.logical_datapath = peer.router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = "outport == ${peer.json_name} && " @@ -6988,7 +6988,7 @@ Flow(.logical_datapath = peer.router.lr._uuid, is_empty_set_or_string(pb.virtual_parent) or pb.chassis == None, sp2 in &SwitchPort(.sw = sp.sw, .peer = Some{peer}), Some{_} = find_lrp_member_ip(peer.networks, IPv4{virtual_ip}). -Flow(.logical_datapath = peer.router.lr._uuid, +Flow(.logical_datapath = peer.router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = "outport == ${peer.json_name} && " @@ -7017,7 +7017,7 @@ for (&SwitchPort(.lsp = lsp1, .peer = Some{&peer1@RouterPort{.router = &peer_router}}, .sw = &sw) if lsp1.is_enabled() and - not peer_router.lr.options.get_bool_def("dynamic_neigh_routers", false)) + not peer_router.options.get_bool_def("dynamic_neigh_routers", false)) { for (&SwitchPort(.lsp = lsp2, .peer = Some{&peer2}, .sw = &Switch{.ls = nb::Logical_Switch{._uuid = sw.ls._uuid}}) @@ -7025,7 +7025,7 @@ for (&SwitchPort(.lsp = lsp1, if peer2.lrp._uuid != peer1.lrp._uuid) { if (not peer2.networks.ipv4_addrs.is_empty()) { - Flow(.logical_datapath = peer_router.lr._uuid, + Flow(.logical_datapath = peer_router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = "outport == ${peer1.json_name} && " @@ -7035,7 +7035,7 @@ for (&SwitchPort(.lsp = lsp1, }; if (not peer2.networks.ipv6_addrs.is_empty()) { - Flow(.logical_datapath = peer_router.lr._uuid, + Flow(.logical_datapath = peer_router._uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 100, .__match = "outport == ${peer1.json_name} && " @@ -7046,15 +7046,15 @@ for (&SwitchPort(.lsp = lsp1, } } -for (&Router(.lr = lr)) +for (&Router(._uuid = lr_uuid)) { - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 0, .__match = "ip4", .actions = "get_arp(outport, ${rEG_NEXT_HOP()}); next;", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ARP_RESOLVE(), .priority = 0, .__match = "ip6", @@ -7075,35 +7075,35 @@ for (&Router(.lr = lr)) * generate ICMPv4 packet with type 3 (Destination Unreachable) and * code 4 (Fragmentation needed). * */ -Flow(.logical_datapath = lr._uuid, +Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_CHK_PKT_LEN(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()) :- - &Router(.lr = lr). -Flow(.logical_datapath = lr._uuid, + &Router(._uuid = lr_uuid). +Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LARGER_PKTS(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()) :- - &Router(.lr = lr). -Flow(.logical_datapath = lr._uuid, + &Router(._uuid = lr_uuid). +Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_CHK_PKT_LEN(), .priority = 50, .__match = "outport == ${l3dgw_port_json_name}", .actions = "${rEGBIT_PKT_LARGER()} = check_pkt_larger(${mtu}); " "next;", .external_ids = stage_hint(l3dgw_port._uuid)) :- - r in &Router(.lr = lr), + r in &Router(._uuid = lr_uuid), Some{var l3dgw_port} = r.l3dgw_port, var l3dgw_port_json_name = json_string_escape(l3dgw_port.name), r.redirect_port_name != "", var gw_mtu = l3dgw_port.options.get_int_def("gateway_mtu", 0), gw_mtu > 0, var mtu = gw_mtu + vLAN_ETH_HEADER_LEN(). -Flow(.logical_datapath = lr._uuid, +Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LARGER_PKTS(), .priority = 50, .__match = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && " @@ -7121,7 +7121,7 @@ Flow(.logical_datapath = lr._uuid, "next(pipeline=ingress, table=0); " "};", .external_ids = stage_hint(rp.lrp._uuid)) :- - r in &Router(.lr = lr), + r in &Router(._uuid = lr_uuid), Some{var l3dgw_port} = r.l3dgw_port, var l3dgw_port_json_name = json_string_escape(l3dgw_port.name), r.redirect_port_name != "", @@ -7130,7 +7130,7 @@ Flow(.logical_datapath = lr._uuid, rp in &RouterPort(.router = r), rp.lrp != l3dgw_port, Some{var first_ipv4} = rp.networks.ipv4_addrs.nth(0). -Flow(.logical_datapath = lr._uuid, +Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_LARGER_PKTS(), .priority = 50, .__match = "inport == ${rp.json_name} && outport == ${l3dgw_port_json_name} && " @@ -7148,7 +7148,7 @@ Flow(.logical_datapath = lr._uuid, "next(pipeline=ingress, table=0); " "};", .external_ids = stage_hint(rp.lrp._uuid)) :- - r in &Router(.lr = lr), + r in &Router(._uuid = lr_uuid), Some{var l3dgw_port} = r.l3dgw_port, var l3dgw_port_json_name = json_string_escape(l3dgw_port.name), r.redirect_port_name != "", @@ -7165,7 +7165,7 @@ Flow(.logical_datapath = lr._uuid, * of the traffic to the l3redirect_port which represents * the central instance of the l3dgw_port. */ -for (&Router(.lr = lr, +for (&Router(._uuid = lr_uuid, .l3dgw_port = l3dgw_port, .redirect_port_name = redirect_port_name)) { @@ -7174,7 +7174,7 @@ for (&Router(.lr = lr, * rule, then the traffic is redirected to the central * instance of the l3dgw_port. */ Some{var gwport} = l3dgw_port in - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_GW_REDIRECT(), .priority = 50, .__match = "outport == ${json_string_escape(gwport.name)}", @@ -7182,7 +7182,7 @@ for (&Router(.lr = lr, .external_ids = stage_hint(gwport._uuid)); /* Packets are allowed by default. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_GW_REDIRECT(), .priority = 0, .__match = "1", @@ -7195,7 +7195,7 @@ for (&Router(.lr = lr, * In the common case where the Ethernet destination has been resolved, * this table outputs the packet (priority 0). Otherwise, it composes * and sends an ARP/IPv6 NA request (priority 100). */ -Flow(.logical_datapath = router.lr._uuid, +Flow(.logical_datapath = router._uuid, .stage = s_ROUTER_IN_ARP_REQUEST(), .priority = 200, .__match = __match, @@ -7216,9 +7216,9 @@ Flow(.logical_datapath = router.lr._uuid, "output; " "};". -for (&Router(.lr = lr)) +for (&Router(._uuid = lr_uuid)) { - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ARP_REQUEST(), .priority = 100, .__match = "eth.dst == 00:00:00:00:00:00 && ip4", @@ -7231,7 +7231,7 @@ for (&Router(.lr = lr)) "};", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ARP_REQUEST(), .priority = 100, .__match = "eth.dst == 00:00:00:00:00:00 && ip6", @@ -7241,7 +7241,7 @@ for (&Router(.lr = lr)) "};", .external_ids = map_empty()); - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_IN_ARP_REQUEST(), .priority = 0, .__match = "1", @@ -7256,7 +7256,7 @@ for (&Router(.lr = lr)) for (&RouterPort(.lrp = lrp, .json_name = json_name, .networks = lrp_networks, - .router = &Router{.lr = lr, .mcast_cfg = &mcast_cfg}) + .router = &Router{._uuid = lr_uuid, .mcast_cfg = &mcast_cfg}) /* Drop packets to disabled logical ports (since logical flow * tables are default-drop). */ if lrp.is_enabled()) @@ -7265,7 +7265,7 @@ for (&RouterPort(.lrp = lrp, * multicast traffic. */ if (mcast_cfg.relay) { - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_DELIVERY(), .priority = 110, .__match = "(ip4.mcast || ip6.mcast) && " @@ -7278,7 +7278,7 @@ for (&RouterPort(.lrp = lrp, * be replaced by the l3dgw port in the local output * pipeline stage before egress processing. */ - Flow(.logical_datapath = lr._uuid, + Flow(.logical_datapath = lr_uuid, .stage = s_ROUTER_OUT_DELIVERY(), .priority = 100, .__match = "outport == ${json_name}", @@ -7424,7 +7424,7 @@ RequestedPortTunKey(datapath, port, tunkey) :- Some{var tunkey} = get_port_tunkey(sp.lsp.options, "requested-tnl-key"). RequestedPortTunKey(datapath, port, tunkey) :- rp in &RouterPort(), - var datapath = rp.router.lr._uuid, + var datapath = rp.router._uuid, var port = rp.lrp._uuid, Some{var tunkey} = get_port_tunkey(rp.lrp.options, "requested-tnl-key"). Warning[message] :- @@ -7928,7 +7928,7 @@ function lrouter_bfd_flows(lr_uuid: uuid, lrp_uuid: uuid, ipX: string, networks: } for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp, .has_bfd = true)) { if (not networks.ipv4_addrs.is_empty()) { - (var a, var b) = lrouter_bfd_flows(router.lr._uuid, lrp._uuid, "ip4", + (var a, var b) = lrouter_bfd_flows(router._uuid, lrp._uuid, "ip4", format_v4_networks(networks, false)) in { Flow[a]; Flow[b] @@ -7936,14 +7936,14 @@ for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp, .has_bfd = }; if (not networks.ipv6_addrs.is_empty()) { - (var a, var b) = lrouter_bfd_flows(router.lr._uuid, lrp._uuid, "ip6", + (var a, var b) = lrouter_bfd_flows(router._uuid, lrp._uuid, "ip6", format_v6_networks(networks)) in { Flow[a]; Flow[b] } } -} - +} + /* Clean up stale FDB entries. */ sb::Out_FDB(_uuid, mac, dp_key, port_key) :- sb::FDB(_uuid, mac, dp_key, port_key), From patchwork Sat Mar 27 00:31:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459074 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6ftq3HvBz9sS8 for ; Sat, 27 Mar 2021 11:32:35 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 186B140644; Sat, 27 Mar 2021 00:32:33 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ItFfm1nF6GoV; Sat, 27 Mar 2021 00:32:30 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTP id 37B9440683; Sat, 27 Mar 2021 00:32:21 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id F0AD7C000B; Sat, 27 Mar 2021 00:32:20 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3A74FC000A for ; Sat, 27 Mar 2021 00:32:19 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id ED6014067A for ; Sat, 27 Mar 2021 00:32:15 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id fCB0WU5U4hhP for ; Sat, 27 Mar 2021 00:32:11 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp2.osuosl.org (Postfix) with ESMTPS id B80D640644 for ; Sat, 27 Mar 2021 00:32:10 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 87BD2FF806; Sat, 27 Mar 2021 00:32:07 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:34 -0700 Message-Id: <20210327003147.2955790-9-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 08/21] ovn-northd-ddlog: Intern the `Router` table. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk This is the first in a series of commits that will replace the use of the DDlog's `Ref<>` type with `Intern<>` throughout the OVN code base. `Ref` and `Intern` are the two forms of smart pointers supported by DDlog at the moment. `Ref` is a reference counted pointer. Copying a `Ref<>` simply increments its reference count. `Intern<>` is an interned object reference. It guarantees that there exists exactly one copy of each unique interned value. Interned objects are slightly more expensive to create, but they have several important advantages: (1) they save memory by deduplicating identical values, (2) they allow by-pointer comparisons, and (3) they avoid unnecessary recomputations in some scenarios. See DDlog docs [1], [2] for more detail. In this commit we change the type of records in the `Router` table from `Ref` to `Intern`. This reduces the amount of churn and speeds up northd significantly in scenarios where the set of router ports changes frequently, which triggers updates to `nb::Logical_Router`, which in turn updates corresponding records in the `Router` table. Interning guarantees that these updates are no-ops and do not trigger any other rules. [1] https://github.com/vmware/differential-datalog/blob/master/doc/tutorial/tutorial.md#reference-type-ref [2] https://github.com/vmware/differential-datalog/blob/master/doc/tutorial/tutorial.md#interned-values-intern-istring Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/lrouter.dl | 21 ++++++++++++--------- northd/multicast.dl | 6 +++--- northd/ovn_northd.dl | 31 +++++++++++++++---------------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/northd/lrouter.dl b/northd/lrouter.dl index 574926b73b67..b2b429af3c96 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -430,7 +430,7 @@ LogicalRouterLBs(lr, vec_empty()) :- function chassis_redirect_name(port_name: string): string = "cr-${port_name}" -relation &Router( +typedef Router = Router { /* Fields copied from nb::Logical_Router. */ _uuid: uuid, name: string, @@ -452,9 +452,12 @@ relation &Router( mcast_cfg: Ref, learn_from_arp_request: bool, force_lb_snat: bool, -) +} + +relation Router[Intern] -&Router(._uuid = lr._uuid, +Router[Router{ + ._uuid = lr._uuid, .name = lr.name, .static_routes = lr.static_routes, .policies = lr.policies, @@ -476,7 +479,7 @@ relation &Router( .lbs = lbs, .mcast_cfg = mcast_cfg, .learn_from_arp_request = learn_from_arp_request, - .force_lb_snat = force_lb_snat) :- + .force_lb_snat = force_lb_snat}.intern()] :- lr in nb::Logical_Router(), lr.is_enabled(), LogicalRouterRedirectPort(lr._uuid, l3dgw_port), @@ -488,7 +491,7 @@ relation &Router( var force_lb_snat = lb_force_snat_router_ip(lr.options). /* RouterLB: many-to-many relation between logical routers and nb::LB */ -relation RouterLB(router: Ref, lb: Ref) +relation RouterLB(router: Intern, lb: Ref) RouterLB(router, lb) :- router in &Router(.lbs = lbs), @@ -496,7 +499,7 @@ RouterLB(router, lb) :- /* Load balancer VIPs associated with routers */ relation RouterLBVIP( - router: Ref, + router: Intern, lb: Ref, vip: string, backends: string) @@ -576,7 +579,7 @@ relation &RouterPort( lrp: nb::Logical_Router_Port, json_name: string, networks: lport_addresses, - router: Ref, + router: Intern, is_redirect: bool, peer: RouterPeer, mcast_cfg: Ref, @@ -711,7 +714,7 @@ function find_lrp_member_ip(networks: lport_addresses, ip: v46_ip): Option, + router : Intern, key : route_key, nexthop : v46_ip, output_port : Option, @@ -735,7 +738,7 @@ typedef route_dst = RouteDst { } relation RouterStaticRoute( - router : Ref, + router : Intern, key : route_key, dsts : Set) diff --git a/northd/multicast.dl b/northd/multicast.dl index 990203bffe25..9b0fa80738d7 100644 --- a/northd/multicast.dl +++ b/northd/multicast.dl @@ -160,7 +160,7 @@ SwitchMcastFloodReportPorts(switch, set_empty()) :- /* Mapping between Router and the set of port uuids on which to * flood IP multicast reports statically. */ -relation RouterMcastFloodPorts(sw: Ref, ports: Set) +relation RouterMcastFloodPorts(sw: Intern, ports: Set) RouterMcastFloodPorts(router, flood_ports) :- &RouterPort( @@ -213,7 +213,7 @@ IgmpSwitchMulticastGroup(address, switch, ports) :- */ relation IgmpRouterGroupPort( address: string, - router : Ref, + router : Intern, port : uuid ) @@ -236,7 +236,7 @@ IgmpRouterGroupPort(address, rtr_port.router, rtr_port.lrp._uuid) :- */ relation IgmpRouterMulticastGroup( address: string, - router : Ref, + router : Intern, ports : Set ) diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index bb8be08dc55e..80d8598bd7dc 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -289,7 +289,7 @@ OutProxy_Port_Binding(._uuid = lrp._uuid, }. /* */ -function get_router_load_balancer_ips(router: Router) : +function get_router_load_balancer_ips(router: Intern) : (Set, Set) = { var all_ips_v4 = set_empty(); @@ -319,8 +319,7 @@ function get_router_load_balancer_ips(router: Router) : function get_nat_addresses(rport: RouterPort): Set = { var addresses = set_empty(); - var router = deref(rport.router); - var has_redirect = router.l3dgw_port.is_some(); + var has_redirect = rport.router.l3dgw_port.is_some(); match (eth_addr_from_string(rport.lrp.mac)) { None -> addresses, Some{mac} -> { @@ -328,7 +327,7 @@ function get_nat_addresses(rport: RouterPort): Set = var central_ip_address = false; /* Get NAT IP addresses. */ - for (nat in router.nats) { + for (nat in rport.router.nats) { /* Determine whether this NAT rule satisfies the conditions for * distributed NAT processing. */ if (has_redirect and nat.nat.__type == "dnat_and_snat" and @@ -371,7 +370,7 @@ function get_nat_addresses(rport: RouterPort): Set = }; /* A set to hold all load-balancer vips. */ - (var all_ips_v4, var all_ips_v6) = get_router_load_balancer_ips(router); + (var all_ips_v4, var all_ips_v6) = get_router_load_balancer_ips(rport.router); for (ip_address in set_union(all_ips_v4, all_ips_v6)) { c_addresses = c_addresses ++ " ${ip_address}"; @@ -382,7 +381,7 @@ function get_nat_addresses(rport: RouterPort): Set = /* Gratuitous ARP for centralized NAT rules on distributed gateway * ports should be restricted to the gateway chassis. */ if (has_redirect) { - c_addresses = c_addresses ++ " is_chassis_resident(${router.redirect_port_name})" + c_addresses = c_addresses ++ " is_chassis_resident(${rport.router.redirect_port_name})" } else (); addresses.insert(c_addresses) @@ -4083,7 +4082,7 @@ function get_arp_forward_ips(rp: Ref): (Set, Set) = var all_ips_v6 = set_empty(); (var lb_ips_v4, var lb_ips_v6) - = get_router_load_balancer_ips(deref(rp.router)); + = get_router_load_balancer_ips(rp.router); for (a in lb_ips_v4) { /* Check if the ovn port has a network configured on which we could * expect ARP requests for the LB VIP. @@ -4852,7 +4851,7 @@ LogicalRouterNatArpNdFlow(router, nat) :- (var ip, var nats) = snat_ip, Some{var nat} = nats.nth(0). -relation LogicalRouterNatArpNdFlow(router: Ref, nat: NAT) +relation LogicalRouterNatArpNdFlow(router: Intern, nat: NAT) LogicalRouterArpNdFlow(router, nat, None, rEG_INPORT_ETH_ADDR(), None, false, 90) :- LogicalRouterNatArpNdFlow(router, nat). @@ -4882,7 +4881,7 @@ LogicalRouterPortNatArpNdFlow(router, nat, l3dgw_port) :- /* Respond to ARP/NS requests on the chassis that binds the gw * port. Drop the ARP/NS requests on other chassis. */ -relation LogicalRouterPortNatArpNdFlow(router: Ref, nat: NAT, lrp: nb::Logical_Router_Port) +relation LogicalRouterPortNatArpNdFlow(router: Intern, nat: NAT, lrp: nb::Logical_Router_Port) LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, Some{extra_match}, false, 92), LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, None, true, 91) :- LogicalRouterPortNatArpNdFlow(router, nat, lrp), @@ -4913,7 +4912,7 @@ LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, None, true, 91) :- /* Now divide the ARP/ND flows into ARP and ND. */ relation LogicalRouterArpNdFlow( - router: Ref, + router: Intern, nat: NAT, lrp: Option, mac: string, @@ -4930,7 +4929,7 @@ LogicalRouterNdFlow(router, lrp, "nd_na", ipv6, true, mac, extra_match, drop, pr mac, extra_match, drop, priority). relation LogicalRouterArpFlow( - lr: Ref, + lr: Intern, lrp: Option, ip: in_addr, mac: string, @@ -4973,7 +4972,7 @@ Flow(.logical_datapath = lr._uuid, }. relation LogicalRouterNdFlow( - lr: Ref, + lr: Intern, lrp: Option, action: string, ip: in6_addr, @@ -5393,7 +5392,7 @@ function lrouter_nat_is_stateless(nat: NAT): bool = { * and action says "next" instead of ct*. */ function lrouter_nat_add_ext_ip_match( - router: Ref, + router: Intern, nat: NAT, __match: string, ipX: string, @@ -6433,7 +6432,7 @@ function numbered_vec(set: Set<'A>) : Vec<(bit<16>, 'A)> = { relation EcmpGroup( group_id: bit<16>, - router: Ref, + router: Intern, key: route_key, dsts: Set, route_match: string, // This is build_route_match(key).0 @@ -6490,7 +6489,7 @@ Flow(.logical_datapath = router._uuid, * an ECMP route need to go through conntrack. */ relation EcmpSymmetricReply( - router: Ref, + router: Intern, dst: route_dst, route_match: string, tunkey: integer) @@ -6712,7 +6711,7 @@ function all_same_addr_family(addrs: Set): bool { } relation EcmpReroutePolicy( - r: Ref, + r: Intern, policy: nb::Logical_Router_Policy, ecmp_group_id: usize ) From patchwork Sat Mar 27 00:31:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459076 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [140.211.166.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fvG39Kbz9sCD for ; Sat, 27 Mar 2021 11:32:58 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 8F4A840684; Sat, 27 Mar 2021 00:32:56 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 8aC03cNWOGeI; Sat, 27 Mar 2021 00:32:54 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTP id 951CC4063F; Sat, 27 Mar 2021 00:32:35 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 63083C000B; Sat, 27 Mar 2021 00:32:35 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 3BFDBC000E for ; Sat, 27 Mar 2021 00:32:33 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id C58BD60DDD for ; Sat, 27 Mar 2021 00:32:18 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6ApjUSaC5h4t for ; Sat, 27 Mar 2021 00:32:15 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp3.osuosl.org (Postfix) with ESMTPS id 0078E60DC6 for ; Sat, 27 Mar 2021 00:32:11 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 3F78BFF805; Sat, 27 Mar 2021 00:32:08 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:35 -0700 Message-Id: <20210327003147.2955790-10-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 09/21] ovn-northd-ddlog: Workaround for slow group_by. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk This patch is a workaround for a performance issue in the DDlog compiler. The issue will hopefully be resolved in a future version of DDlog, but for now we need this and possibly a few other similar fixes. Here is one affected rule: ``` sb::Out_Port_Group(._uuid = hash128(sb_name), .name = sb_name, .ports = port_names) :- nb::Port_Group(._uuid = _uuid, .name = nb_name, .ports = pg_ports), var port_uuid = FlatMap(pg_ports), &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{._uuid = port_uuid, .name = port_name}, .sw = &Switch{.ls = nb::Logical_Switch{._uuid = ls_uuid}}), TunKeyAllocation(.datapath = ls_uuid, .tunkey = tunkey), var sb_name = "${tunkey}_${nb_name}", var port_names = port_name.group_by((_uuid, sb_name)).to_set(). ``` The first literal in the body of the rule binds variable `pg_ports` to the array of ports in the port group. This is a potentially large array that immediately gets flattened by the `FlatMap` operator. Since the `pg_ports` variable is not used in the remainder of the rule, DDlog normally would not propagate it through the rest of the rule. Unfortunately, due to a subtle semantic quirk, the behavior is different when there is a `group_by` operator further down in the rule, in which case unused variables are still propagated through the rule, which involves expensive copies. The workaround I implemented factors the first two terms in the rule into a separate `PortGroupPort` relation, so that the ports array no longer occurs in the new version of the rule: ``` sb::Out_Port_Group(._uuid = hash128(sb_name), .name = sb_name, .ports = port_names) :- PortGroupPort(.pg_uuid = _uuid, .pg_name = nb_name, .port = port_uuid), &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{._uuid = port_uuid, .name = port_name}, .sw = &Switch{.ls = nb::Logical_Switch{._uuid = ls_uuid}}), TunKeyAllocation(.datapath = ls_uuid, .tunkey = tunkey), var sb_name = "${tunkey}_${nb_name}", var port_names = port_name.group_by((_uuid, sb_name)).to_set(). ``` Again, benchmarking is likely to reveal more instances of this. A proper fix will require a change to the DDlog compiler. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/ovn_northd.dl | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 80d8598bd7dc..5a7a11295964 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -712,11 +712,10 @@ sb::Out_Address_Set(._uuid = hash128("svc_monitor_mac"), SvcMonitorMac(svc_monitor_mac). sb::Out_Address_Set(hash128(as_name), as_name, pg_ip4addrs.union()) :- - nb::Port_Group(.ports = pg_ports, .name = pg_name), + PortGroupPort(.pg_name = pg_name, .port = port_uuid), var as_name = pg_name ++ "_ip4", // avoid name collisions with user-defined Address_Sets not nb::Address_Set(.name = as_name), - var port_uuid = FlatMap(pg_ports), PortStaticAddresses(.lsport = port_uuid, .ip4addrs = stat), SwitchPortNewDynamicAddress(&SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = port_uuid}}, dyn_addr), @@ -738,11 +737,10 @@ sb::Out_Address_Set(hash128(as_name), as_name, set_empty()) :- not nb::Address_Set(.name = as_name). sb::Out_Address_Set(hash128(as_name), as_name, pg_ip6addrs.union()) :- - nb::Port_Group(.ports = pg_ports, .name = pg_name), + PortGroupPort(.pg_name = pg_name, .port = port_uuid), var as_name = pg_name ++ "_ip6", // avoid name collisions with user-defined Address_Sets not nb::Address_Set(.name = as_name), - var port_uuid = FlatMap(pg_ports), PortStaticAddresses(.lsport = port_uuid, .ip6addrs = stat), SwitchPortNewDynamicAddress(&SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = port_uuid}}, dyn_addr), @@ -771,9 +769,18 @@ sb::Out_Address_Set(hash128(as_name), as_name, set_empty()) :- * SB Port_Group.name uniqueness constraint, ovn-northd populates the field * with the value: _. */ + +relation PortGroupPort( + pg_uuid: uuid, + pg_name: string, + port: uuid) + +PortGroupPort(pg_uuid, pg_name, port) :- + nb::Port_Group(._uuid = pg_uuid, .name = pg_name, .ports = pg_ports), + var port = FlatMap(pg_ports). + sb::Out_Port_Group(._uuid = hash128(sb_name), .name = sb_name, .ports = port_names) :- - nb::Port_Group(._uuid = _uuid, .name = nb_name, .ports = pg_ports), - var port_uuid = FlatMap(pg_ports), + PortGroupPort(.pg_uuid = _uuid, .pg_name = nb_name, .port = port_uuid), &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{._uuid = port_uuid, .name = port_name}, .sw = &Switch{.ls = nb::Logical_Switch{._uuid = ls_uuid}}), From patchwork Sat Mar 27 00:31:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459077 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fvK4VxNz9sCD for ; Sat, 27 Mar 2021 11:33:01 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 2F9614193B; Sat, 27 Mar 2021 00:32:59 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 7MVMOFAUbBji; Sat, 27 Mar 2021 00:32:57 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTP id 524694193A; Sat, 27 Mar 2021 00:32:39 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 2BA97C0019; Sat, 27 Mar 2021 00:32:36 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1788CC000B for ; Sat, 27 Mar 2021 00:32:35 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id EDF2B406A8 for ; Sat, 27 Mar 2021 00:32:24 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id AOAa_cpouU5D for ; Sat, 27 Mar 2021 00:32:21 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp2.osuosl.org (Postfix) with ESMTPS id 8E4A840663 for ; Sat, 27 Mar 2021 00:32:13 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id E8CF2FF803; Sat, 27 Mar 2021 00:32:10 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:36 -0700 Message-Id: <20210327003147.2955790-11-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 10/21] ovn-northd-ddlog: Intern the Switch table. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Change the type of record in the `Switch` table from `Ref` to `Intern`. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/lswitch.dl | 37 +++++++++++++++++++++---------------- northd/multicast.dl | 10 +++++----- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/northd/lswitch.dl b/northd/lswitch.dl index 47c497e0cff7..218272206e05 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -186,7 +186,7 @@ LogicalSwitchHasNonRouterPort(ls, false) :- /* Switch relation collects all attributes of a logical switch */ -relation &Switch( +typedef Switch = Switch { ls: nb::Logical_Switch, has_stateful_acl: bool, has_lb_vip: bool, @@ -200,7 +200,10 @@ relation &Switch( /* Does this switch have at least one port with type != "router"? */ has_non_router_port: bool -) +} + + +relation Switch[Intern] function ipv6_parse_prefix(s: string): Option { if (string_contains(s, "/")) { @@ -213,17 +216,19 @@ function ipv6_parse_prefix(s: string): Option { } } -&Switch(.ls = ls, - .has_stateful_acl = has_stateful_acl, - .has_lb_vip = has_lb_vip, - .has_dns_records = has_dns_records, - .has_unknown_ports = has_unknown_ports, - .localnet_ports = localnet_ports, - .subnet = subnet, - .ipv6_prefix = ipv6_prefix, - .mcast_cfg = mcast_cfg, - .has_non_router_port = has_non_router_port, - .is_vlan_transparent = is_vlan_transparent) :- +Switch[Switch{ + .ls = ls, + .has_stateful_acl = has_stateful_acl, + .has_lb_vip = has_lb_vip, + .has_dns_records = has_dns_records, + .has_unknown_ports = has_unknown_ports, + .localnet_ports = localnet_ports, + .subnet = subnet, + .ipv6_prefix = ipv6_prefix, + .mcast_cfg = mcast_cfg, + .has_non_router_port = has_non_router_port, + .is_vlan_transparent = is_vlan_transparent + }.intern()] :- nb::Logical_Switch[ls], LogicalSwitchHasStatefulACL(ls._uuid, has_stateful_acl), LogicalSwitchHasLBVIP(ls._uuid, has_lb_vip), @@ -449,7 +454,7 @@ SwitchPortDHCPv6Options(port, options) :- options in &DHCP_OptionsRef[nb::DHCP_Options{._uuid = dhcpv6_uuid}]. /* SwitchQoS: many-to-one relation between logical switches and nb::QoS */ -relation SwitchQoS(sw: Ref, qos: Ref) +relation SwitchQoS(sw: Intern, qos: Ref) SwitchQoS(sw, qos) :- sw in &Switch(.ls = nb::Logical_Switch{.qos_rules = qos_rules}), @@ -475,7 +480,7 @@ ACLWithFairMeter(acl, meter) :- meter in &MeterRef[nb::Meter{.name = meter_name, .fair = Some{true}}]. /* SwitchACL: many-to-many relation between logical switches and ACLs */ -relation &SwitchACL(sw: Ref, +relation &SwitchACL(sw: Intern, acl: Ref, has_fair_meter: bool) @@ -536,7 +541,7 @@ SwitchPortHAChassisGroup(lsp_uuid, None) :- relation &SwitchPort( lsp: nb::Logical_Switch_Port, json_name: string, - sw: Ref, + sw: Intern, peer: Option>, static_addresses: Vec, dynamic_address: Option, diff --git a/northd/multicast.dl b/northd/multicast.dl index 9b0fa80738d7..5a14a90da1cd 100644 --- a/northd/multicast.dl +++ b/northd/multicast.dl @@ -100,7 +100,7 @@ relation &McastPortCfg( /* Mapping between Switch and the set of router port uuids on which to flood * IP multicast for relay. */ -relation SwitchMcastFloodRelayPorts(sw: Ref, ports: Set) +relation SwitchMcastFloodRelayPorts(sw: Intern, ports: Set) SwitchMcastFloodRelayPorts(switch, relay_ports) :- &SwitchPort( @@ -124,7 +124,7 @@ SwitchMcastFloodRelayPorts(switch, set_empty()) :- /* Mapping between Switch and the set of port uuids on which to * flood IP multicast statically. */ -relation SwitchMcastFloodPorts(sw: Ref, ports: Set) +relation SwitchMcastFloodPorts(sw: Intern, ports: Set) SwitchMcastFloodPorts(switch, flood_ports) :- &SwitchPort( @@ -142,7 +142,7 @@ SwitchMcastFloodPorts(switch, set_empty()) :- /* Mapping between Switch and the set of port uuids on which to * flood IP multicast reports statically. */ -relation SwitchMcastFloodReportPorts(sw: Ref, ports: Set) +relation SwitchMcastFloodReportPorts(sw: Intern, ports: Set) SwitchMcastFloodReportPorts(switch, flood_ports) :- &SwitchPort( @@ -179,7 +179,7 @@ RouterMcastFloodPorts(router, set_empty()) :- /* Flattened IGMP group. One record per address-port tuple. */ relation IgmpSwitchGroupPort( address: string, - switch : Ref, + switch : Intern, port : uuid ) @@ -199,7 +199,7 @@ IgmpSwitchGroupPort(address, switch, localnet_port.0) :- */ relation IgmpSwitchMulticastGroup( address: string, - switch : Ref, + switch : Intern, ports : Set ) From patchwork Sat Mar 27 00:31:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459081 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fw34375z9sCD for ; Sat, 27 Mar 2021 11:33:39 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 7969384E39; Sat, 27 Mar 2021 00:33:36 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id r2mlqC3jIXdA; Sat, 27 Mar 2021 00:33:28 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTP id C787D84DDE; Sat, 27 Mar 2021 00:33:01 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 7B969C000B; Sat, 27 Mar 2021 00:33:01 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 16593C000A for ; Sat, 27 Mar 2021 00:33:00 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id D697984DB4 for ; Sat, 27 Mar 2021 00:32:35 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id lLZf1Yo4gpAt for ; Sat, 27 Mar 2021 00:32:26 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id 6F20184D9D for ; Sat, 27 Mar 2021 00:32:15 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 9777CFF806; Sat, 27 Mar 2021 00:32:12 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:37 -0700 Message-Id: <20210327003147.2955790-12-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 11/21] ovn-northd-ddlog: Remove `ls` field from `Switch`. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk This commit is analogous to 076749c99, but switches instead of routers. `relation Switch` stores the internal representation of a logical switch, consisting of values from the `nb::Logical_Switch` table augmented with some additional fields. We used to do this by copying the entire `Logical_Switch` record inside `Switch`. This proved highly inefficient in scenarios where some of the entities that `Logical_Switch` references (logicl switch ports, ACLs, or QoS rules) change frequently. Every such change modifies the `Logical_Switch` record, which triggers an update of the `Switch` object, which can cause a bunch of rules to update their outputs. As a workaround, we no longer store the entire `Logical_Switch` object in the `Switch` table, and instead only copy its relevant fields. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/ipam.dl | 25 ++- northd/lswitch.dl | 24 ++- northd/ovn_northd.dl | 356 ++++++++++++++++++++++--------------------- 3 files changed, 210 insertions(+), 195 deletions(-) diff --git a/northd/ipam.dl b/northd/ipam.dl index 589126f81288..e7373f250a7f 100644 --- a/northd/ipam.dl +++ b/northd/ipam.dl @@ -95,18 +95,17 @@ function parse_dynamic_address_request(s: string): Option) /* Add reserved address groups (1) and (2). */ -SwitchIPv4ReservedAddress(.lswitch = ls._uuid, +SwitchIPv4ReservedAddress(.lswitch = sw._uuid, .addr = addr) :- - &Switch(.ls = ls, - .subnet = Some{(_, _, start_ipv4, total_ipv4s)}), + sw in &Switch(.subnet = Some{(_, _, start_ipv4, total_ipv4s)}), var exclude_ips = { var exclude_ips = set_singleton(start_ipv4); exclude_ips.insert(start_ipv4 + total_ipv4s - 1); - match (map_get(ls.other_config, "exclude_ips")) { + match (map_get(sw.other_config, "exclude_ips")) { None -> exclude_ips, Some{exclude_ip_list} -> match (parse_ip_list(exclude_ip_list)) { Left{err} -> { - warn("logical switch ${uuid2str(ls._uuid)}: bad exclude_ips (${err})"); + warn("logical switch ${uuid2str(sw._uuid)}: bad exclude_ips (${err})"); exclude_ips }, Right{ranges} -> { @@ -124,7 +123,7 @@ SwitchIPv4ReservedAddress(.lswitch = ls._uuid, exclude_ips.insert(addr) } } else { - warn("logical switch ${uuid2str(ls._uuid)}: excluded addresses not in subnet") + warn("logical switch ${uuid2str(sw._uuid)}: excluded addresses not in subnet") } }; exclude_ips @@ -135,11 +134,11 @@ SwitchIPv4ReservedAddress(.lswitch = ls._uuid, var addr = FlatMap(exclude_ips). /* Add reserved address group (3). */ -SwitchIPv4ReservedAddress(.lswitch = ls._uuid, +SwitchIPv4ReservedAddress(.lswitch = ls_uuid, .addr = addr) :- SwitchPortStaticAddresses( .port = &SwitchPort{ - .sw = &Switch{.ls = ls, + .sw = &Switch{._uuid = ls_uuid, .subnet = Some{(_, _, start_ipv4, total_ipv4s)}}, .peer = None}, .addrs = lport_addrs @@ -157,10 +156,10 @@ SwitchIPv4ReservedAddress(.lswitch = ls._uuid, var addr = FlatMap(addrs). /* Add reserved address group (4) */ -SwitchIPv4ReservedAddress(.lswitch = ls._uuid, +SwitchIPv4ReservedAddress(.lswitch = ls_uuid, .addr = addr) :- &SwitchPort( - .sw = &Switch{.ls = ls, + .sw = &Switch{._uuid = ls_uuid, .subnet = Some{(_, _, start_ipv4, total_ipv4s)}}, .peer = Some{&rport}), var addrs = { @@ -176,7 +175,7 @@ SwitchIPv4ReservedAddress(.lswitch = ls._uuid, var addr = FlatMap(addrs). /* Add reserved address group (5) */ -SwitchIPv4ReservedAddress(.lswitch = sw.ls._uuid, +SwitchIPv4ReservedAddress(.lswitch = sw._uuid, .addr = ip_addr.a) :- &SwitchPort(.sw = &sw, .lsp = lsp, .static_dynamic_ipv4 = Some{ip_addr}). @@ -199,7 +198,7 @@ SwitchPortAllocatedIPv4DynAddress(lsport, dyn_addr) :- /* Aggregate all ports of a switch that need a dynamic IP address */ port in &SwitchPort(.needs_dynamic_ipv4address = true, .sw = &sw), - var switch_id = sw.ls._uuid, + var switch_id = sw._uuid, var ports = port.group_by(switch_id).to_vec(), SwitchIPv4ReservedAddresses(switch_id, reserved_addrs), /* Allocate dynamic addresses only for ports that don't have a dynamic address @@ -437,7 +436,7 @@ SwitchPortNewMACDynAddress(lsp._uuid, mac_addr) :- None -> None, Some{addr} -> { if (sw.subnet.is_some() or sw.ipv6_prefix.is_some() or - map_get(sw.ls.other_config, "mac_only") == Some{"true"}) { + map_get(sw.other_config, "mac_only") == Some{"true"}) { Some{addr} } else { None diff --git a/northd/lswitch.dl b/northd/lswitch.dl index 218272206e05..25abd0aa8189 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -187,7 +187,14 @@ LogicalSwitchHasNonRouterPort(ls, false) :- /* Switch relation collects all attributes of a logical switch */ typedef Switch = Switch { - ls: nb::Logical_Switch, + /* Fields copied from nb::Logical_Switch_Port. */ + _uuid: uuid, + name: string, + load_balancer: Set, + other_config: Map, + external_ids: Map, + + /* Additional computed fields. */ has_stateful_acl: bool, has_lb_vip: bool, has_dns_records: bool, @@ -217,7 +224,12 @@ function ipv6_parse_prefix(s: string): Option { } Switch[Switch{ - .ls = ls, + ._uuid = ls._uuid, + .name = ls.name, + .load_balancer = ls.load_balancer, + .other_config = ls.other_config, + .external_ids = ls.external_ids, + .has_stateful_acl = has_stateful_acl, .has_lb_vip = has_lb_vip, .has_dns_records = has_dns_records, @@ -457,7 +469,8 @@ SwitchPortDHCPv6Options(port, options) :- relation SwitchQoS(sw: Intern, qos: Ref) SwitchQoS(sw, qos) :- - sw in &Switch(.ls = nb::Logical_Switch{.qos_rules = qos_rules}), + sw in &Switch(), + nb::Logical_Switch(._uuid = sw._uuid, .qos_rules = qos_rules), var qos_rule = FlatMap(qos_rules), qos in &QoSRef[nb::QoS{._uuid = qos_rule}]. @@ -486,7 +499,7 @@ relation &SwitchACL(sw: Intern, &SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = has_fair_meter) :- LogicalSwitchACL(sw_uuid, acl_uuid), - sw in &Switch(.ls = nb::Logical_Switch{._uuid = sw_uuid}), + sw in &Switch(._uuid = sw_uuid), acl in &ACLRef[nb::ACL{._uuid = acl_uuid}], ACLHasFairMeter(acl, has_fair_meter). @@ -581,7 +594,8 @@ relation &SwitchPort( .hac_group_uuid = hac_group_uuid) :- nb::Logical_Switch_Port[lsp], LogicalSwitchPort(lsp._uuid, lswitch_uuid), - sw in &Switch(.ls = nb::Logical_Switch{._uuid = lswitch_uuid, .other_config = other_config}, + sw in &Switch(._uuid = lswitch_uuid, + .other_config = other_config, .subnet = subnet, .ipv6_prefix = ipv6_prefix), SwitchRouterPeerRef(lsp._uuid, peer), diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 5a7a11295964..1745adcf8949 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -126,7 +126,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, .gateway_chassis = set_empty(), .ha_chassis_group = sp.hac_group_uuid, .options = lsp.options, - .datapath = sw.ls._uuid, + .datapath = sw._uuid, .parent_port = lsp.parent_name, .tag = tag, .mac = lsp.addresses, @@ -156,7 +156,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, .gateway_chassis = set_empty(), .ha_chassis_group = None, .options = options, - .datapath = sw.ls._uuid, + .datapath = sw._uuid, .parent_port = lsp.parent_name, .tag = None, .mac = lsp.addresses, @@ -552,7 +552,7 @@ sb::Out_HA_Chassis(ha_chassis_uuid(ha_chassis.chassis_name, hac_uuid), chassis, sb::Out_HA_Chassis_Group(_uuid, name, ha_chassis, set_empty() /* XXX? */, eids) :- sp in &SwitchPort(), sp.lsp.__type == "external", - var ls_uuid = sp.sw.ls._uuid, + var ls_uuid = sp.sw._uuid, Some{var ha_chassis_group_uuid} = sp.lsp.ha_chassis_group, ha_chassis_group in nb::HA_Chassis_Group(._uuid = ha_chassis_group_uuid, .name = name, .external_ids = eids), @@ -783,7 +783,7 @@ sb::Out_Port_Group(._uuid = hash128(sb_name), .name = sb_name, .ports = port_nam PortGroupPort(.pg_uuid = _uuid, .pg_name = nb_name, .port = port_uuid), &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{._uuid = port_uuid, .name = port_name}, - .sw = &Switch{.ls = nb::Logical_Switch{._uuid = ls_uuid}}), + .sw = &Switch{._uuid = ls_uuid}), TunKeyAllocation(.datapath = ls_uuid, .tunkey = tunkey), var sb_name = "${tunkey}_${nb_name}", var port_names = port_name.group_by((_uuid, sb_name)).to_set(). @@ -839,9 +839,9 @@ sb::Out_Multicast_Group (._uuid = hash128((datapath,name)), .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- - &SwitchPort(.lsp = lsp, .sw = &Switch{.ls = ls}), + &SwitchPort(.lsp = lsp, .sw = sw), lsp.is_enabled(), - var datapath = ls._uuid, + var datapath = sw._uuid, var port_ids = lsp._uuid.group_by((datapath)).to_set(), (var name, var tunnel_key) = mC_FLOOD(). @@ -852,10 +852,10 @@ sb::Out_Multicast_Group (._uuid = hash128((datapath,name)), .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- - &SwitchPort(.lsp = lsp, .sw = &Switch{.ls = ls}), + &SwitchPort(.lsp = lsp, .sw = sw), lsp.is_enabled(), lsp.__type != "router", - var datapath = ls._uuid, + var datapath = sw._uuid, var port_ids = lsp._uuid.group_by((datapath)).to_set(), (var name, var tunnel_key) = mC_FLOOD_L2(). @@ -872,8 +872,8 @@ sb::Out_Multicast_Group (._uuid = hash128((ls,name)), /* Create a multicast group to flood multicast traffic to routers with * multicast relay enabled. */ -sb::Out_Multicast_Group (._uuid = hash128((sw.ls._uuid,name)), - .datapath = sw.ls._uuid, +sb::Out_Multicast_Group (._uuid = hash128((sw._uuid,name)), + .datapath = sw._uuid, .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- @@ -884,8 +884,8 @@ sb::Out_Multicast_Group (._uuid = hash128((sw.ls._uuid,name)), /* Create a multicast group to flood traffic (no reports) to ports with * multicast flood enabled. */ -sb::Out_Multicast_Group (._uuid = hash128((sw.ls._uuid,name)), - .datapath = sw.ls._uuid, +sb::Out_Multicast_Group (._uuid = hash128((sw._uuid,name)), + .datapath = sw._uuid, .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- @@ -896,8 +896,8 @@ sb::Out_Multicast_Group (._uuid = hash128((sw.ls._uuid,name)), /* Create a multicast group to flood reports to ports with * multicast flood_reports enabled. */ -sb::Out_Multicast_Group (._uuid = hash128((sw.ls._uuid,name)), - .datapath = sw.ls._uuid, +sb::Out_Multicast_Group (._uuid = hash128((sw._uuid,name)), + .datapath = sw._uuid, .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- @@ -920,7 +920,7 @@ sb::Out_Multicast_Group (._uuid = hash128((rtr._uuid,name)), /* Create a multicast group for each IGMP group learned by a Switch. * 'tunnel_key' == 0 triggers an ID allocation later. */ -OutProxy_Multicast_Group (.datapath = switch.ls._uuid, +OutProxy_Multicast_Group (.datapath = switch._uuid, .name = address, .ports = port_ids) :- IgmpSwitchMulticastGroup(address, &switch, port_ids). @@ -1687,14 +1687,15 @@ for (f in AggregatedFlow()) { } /* Logical flows for forwarding groups. */ -Flow(.logical_datapath = sw.ls._uuid, +Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 50, .__match = __match, .actions = actions, .external_ids = stage_hint(fg_uuid)) :- sw in &Switch(), - var fg_uuid = FlatMap(sw.ls.forwarding_groups), + nb::Logical_Switch(._uuid = sw._uuid, .forwarding_groups = forwarding_groups), + var fg_uuid = FlatMap(forwarding_groups), fg in nb::Forwarding_Group(._uuid = fg_uuid), not fg.child_port.is_empty(), var __match = "arp.tpa == ${fg.vip} && arp.op == 1", @@ -1716,14 +1717,15 @@ function escape_child_ports(child_port: Set): string { }; escaped.join(",") } -Flow(.logical_datapath = sw.ls._uuid, +Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 50, .__match = __match, .actions = actions, .external_ids = map_empty()) :- sw in &Switch(), - var fg_uuid = FlatMap(sw.ls.forwarding_groups), + nb::Logical_Switch(._uuid = sw._uuid, .forwarding_groups = forwarding_groups), + var fg_uuid = FlatMap(forwarding_groups), fg in nb::Forwarding_Group(._uuid = fg_uuid), not fg.child_port.is_empty(), var __match = "eth.dst == ${fg.vmac}", @@ -1736,7 +1738,7 @@ Flow(.logical_datapath = sw.ls._uuid, for (sw in &Switch()) { if (not sw.is_vlan_transparent) { /* Block logical VLANs. */ - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_L2(), .priority = 100, .__match = "vlan.present", @@ -1745,7 +1747,7 @@ for (sw in &Switch()) { }; /* Broadcast/multicast source address is invalid */ - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_L2(), .priority = 100, .__match = "eth.src[40]", @@ -1802,29 +1804,29 @@ function build_port_security_ipv6_nd_flow( } /* Pre-ACL */ -for (&Switch(.ls =ls)) { +for (&Switch(._uuid =ls_uuid)) { /* Ingress and Egress Pre-ACL Table (Priority 0): Packets are * allowed by default. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_ACL(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_ACL(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_ACL(), .priority = 110, .__match = "eth.dst == $svc_monitor_mac", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_ACL(), .priority = 110, .__match = "eth.src == $svc_monitor_mac", @@ -1839,7 +1841,7 @@ for (&Switch(.ls =ls)) { for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "router"}, .json_name = lsp_name, - .sw = &Switch{.ls = ls, .has_stateful_acl = true})) { + .sw = &Switch{._uuid = ls_uuid, .has_stateful_acl = true})) { /* Can't use ct() for router ports. Consider the * following configuration: lp1(10.0.0.2) on * hostA--ls1--lr0--ls2--lp2(10.0.1.2) on hostB, For a @@ -1852,13 +1854,13 @@ for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "router"}, * as the icmp request went through the logical router * on hostA, not hostB. This would only work with * distributed conntrack state across all chassis. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_ACL(), .priority = 110, .__match = "ip && inport == ${lsp_name}", .actions = "next;", .external_ids = stage_hint(lsp._uuid)); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_ACL(), .priority = 110, .__match = "ip && outport == ${lsp_name}", @@ -1868,14 +1870,14 @@ for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "router"}, for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "localnet"}, .json_name = lsp_name, - .sw = &Switch{.ls = ls, .has_stateful_acl = true})) { - Flow(.logical_datapath = ls._uuid, + .sw = &Switch{._uuid = ls_uuid, .has_stateful_acl = true})) { + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_ACL(), .priority = 110, .__match = "ip && inport == ${lsp_name}", .actions = "next;", .external_ids = stage_hint(lsp._uuid)); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_ACL(), .priority = 110, .__match = "ip && outport == ${lsp_name}", @@ -1883,19 +1885,19 @@ for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "localnet"}, .external_ids = stage_hint(lsp._uuid)) } -for (&Switch(.ls = ls, .has_stateful_acl = true)) { +for (&Switch(._uuid = ls_uuid, .has_stateful_acl = true)) { /* Ingress and Egress Pre-ACL Table (Priority 110). * * Not to do conntrack on ND and ICMP destination * unreachable packets. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_ACL(), .priority = 110, .__match = "nd || nd_rs || nd_ra || mldv1 || mldv2 || " "(udp && udp.src == 546 && udp.dst == 547)", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_ACL(), .priority = 110, .__match = "nd || nd_rs || nd_ra || mldv1 || mldv2 || " @@ -1911,13 +1913,13 @@ for (&Switch(.ls = ls, .has_stateful_acl = true)) { * * 'REGBIT_CONNTRACK_DEFRAG' is set to let the pre-stateful table send * it to conntrack for tracking and defragmentation. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_ACL(), .priority = 100, .__match = "ip", .actions = "${rEGBIT_CONNTRACK_DEFRAG()} = 1; next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_ACL(), .priority = 100, .__match = "ip", @@ -1926,16 +1928,16 @@ for (&Switch(.ls = ls, .has_stateful_acl = true)) { } /* Pre-LB */ -for (&Switch(.ls = ls)) { +for (&Switch(._uuid = ls_uuid)) { /* Do not send ND packets to conntrack */ var __match = "nd || nd_rs || nd_ra || mldv1 || mldv2" in { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_LB(), .priority = 110, .__match = __match, .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_LB(), .priority = 110, .__match = __match, @@ -1944,13 +1946,13 @@ for (&Switch(.ls = ls)) { }; /* Do not send service monitor packets to conntrack. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_LB(), .priority = 110, .__match = "eth.dst == $svc_monitor_mac", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_LB(), .priority = 110, .__match = "eth.src == $svc_monitor_mac", @@ -1958,13 +1960,13 @@ for (&Switch(.ls = ls)) { .external_ids = map_empty()); /* Allow all packets to go to next tables by default. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_LB(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_LB(), .priority = 0, .__match = "1", @@ -1972,15 +1974,15 @@ for (&Switch(.ls = ls)) { .external_ids = map_empty()) } -for (&SwitchPort(.lsp = lsp, .json_name = lsp_name, .sw = &Switch{.ls = ls})) +for (&SwitchPort(.lsp = lsp, .json_name = lsp_name, .sw = &Switch{._uuid = ls_uuid})) if (lsp.__type == "router" or lsp.__type == "localnet") { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_LB(), .priority = 110, .__match = "ip && inport == ${lsp_name}", .actions = "next;", .external_ids = stage_hint(lsp._uuid)); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_LB(), .priority = 110, .__match = "ip && outport == ${lsp_name}", @@ -2051,7 +2053,7 @@ LoadBalancerEmptyEvents(lb) :- var local_events = local_options.get_bool_def("event", false), global_events or local_events. -Flow(.logical_datapath = sw.ls._uuid, +Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PRE_LB(), .priority = 130, .__match = __match, @@ -2060,7 +2062,7 @@ Flow(.logical_datapath = sw.ls._uuid, SwitchLBVIP(.sw_uuid = sw_uuid, .lb = lb, .vip = vip, .backends = backends), LoadBalancerEmptyEvents(lb), not lb.options.get_bool_def("reject", false), - sw in &Switch(.ls = nb::Logical_Switch{._uuid = sw_uuid}), + sw in &Switch(._uuid = sw_uuid), backends == "", HasEventElbMeter(has_elb_meter), Some {(var __match, var __action)} = build_empty_lb_event_flow( @@ -2096,13 +2098,13 @@ Flow(.logical_datapath = sw.ls._uuid, * add a lflow to drop ct.inv packets. */ for (sw in &Switch(.has_lb_vip = true)) { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PRE_LB(), .priority = 100, .__match = "ip", .actions = "${rEGBIT_CONNTRACK_DEFRAG()} = 1; next;", .external_ids = map_empty()); - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_PRE_LB(), .priority = 100, .__match = "ip", @@ -2111,16 +2113,16 @@ for (sw in &Switch(.has_lb_vip = true)) { } /* Pre-stateful */ -for (&Switch(.ls = ls)) { +for (&Switch(._uuid = ls_uuid)) { /* Ingress and Egress pre-stateful Table (Priority 0): Packets are * allowed by default. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_STATEFUL(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_STATEFUL(), .priority = 0, .__match = "1", @@ -2129,13 +2131,13 @@ for (&Switch(.ls = ls)) { /* If REGBIT_CONNTRACK_DEFRAG is set as 1, then the packets should be * sent to conntrack for tracking and defragmentation. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PRE_STATEFUL(), .priority = 100, .__match = "${rEGBIT_CONNTRACK_DEFRAG()} == 1", .actions = "ct_next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PRE_STATEFUL(), .priority = 100, .__match = "${rEGBIT_CONNTRACK_DEFRAG()} == 1", @@ -2246,19 +2248,19 @@ for (Reject(lsuuid, pipeline, stage, acl, fair_meter, extra_match_, extra_action } /* build_acls */ -for (sw in &Switch(.ls = ls)) +for (sw in &Switch(._uuid = ls_uuid)) var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in { /* Ingress and Egress ACL Table (Priority 0): Packets are allowed by * default. A related rule at priority 1 is added below if there * are any stateful ACLs in this datapath. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_ACL(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 0, .__match = "1", @@ -2287,13 +2289,13 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in * which will be done by ct_commit() in the "stateful" stage. * Subsequent packets will hit the flow at priority 0 that just * uses "next;". */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_ACL(), .priority = 1, .__match = "ip && (!ct.est || (ct.est && ct_label.blocked == 1))", .actions = "${rEGBIT_CONNTRACK_COMMIT()} = 1; next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 1, .__match = "ip && (!ct.est || (ct.est && ct_label.blocked == 1))", @@ -2307,13 +2309,13 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in * for deletion (bit 0 of ct_label is set). * * This is enforced at a higher priority than ACLs can be defined. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_ACL(), .priority = 65535, .__match = "ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)", .actions = "drop;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 65535, .__match = "ct.inv || (ct.est && ct.rpl && ct_label.blocked == 1)", @@ -2329,14 +2331,14 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in * direction to hit the currently defined policy from ACLs. * * This is enforced at a higher priority than ACLs can be defined. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_ACL(), .priority = 65535, .__match = "ct.est && !ct.rel && !ct.new && !ct.inv " "&& ct.rpl && ct_label.blocked == 0", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 65535, .__match = "ct.est && !ct.rel && !ct.new && !ct.inv " @@ -2355,14 +2357,14 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in * a dynamically negotiated FTP data channel), but will allow * related traffic such as an ICMP Port Unreachable through * that's generated from a non-listening UDP port. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_ACL(), .priority = 65535, .__match = "!ct.est && ct.rel && !ct.new && !ct.inv " "&& ct_label.blocked == 0", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 65535, .__match = "!ct.est && ct.rel && !ct.new && !ct.inv " @@ -2373,13 +2375,13 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in /* Ingress and Egress ACL Table (Priority 65535). * * Not to do conntrack on ND packets. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_ACL(), .priority = 65535, .__match = "nd || nd_ra || nd_rs || mldv1 || mldv2", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 65535, .__match = "nd || nd_ra || nd_rs || mldv1 || mldv2", @@ -2391,7 +2393,7 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in * if the CMS has configured DNS records for the datapath. */ if (sw.has_dns_records) { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 34000, .__match = "udp.src == 53", @@ -2401,13 +2403,13 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in /* Add a 34000 priority flow to advance the service monitor reply * packets to skip applying ingress ACLs. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_ACL(), .priority = 34000, .__match = "eth.dst == $svc_monitor_mac", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 34000, .__match = "eth.src == $svc_monitor_mac", @@ -2430,10 +2432,10 @@ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in input relation AclHintStages[Stage] AclHintStages[s_SWITCH_IN_ACL_HINT()]. AclHintStages[s_SWITCH_OUT_ACL_HINT()]. -for (sw in &Switch(.ls = ls)) { +for (sw in &Switch(._uuid = ls_uuid)) { for (AclHintStages[stage]) { /* In any case, advance to the next stage. */ - Flow(ls._uuid, stage, 0, "1", "next;", map_empty()) + Flow(ls_uuid, stage, 0, "1", "next;", map_empty()) }; for (AclHintStages[stage]) @@ -2442,7 +2444,7 @@ for (sw in &Switch(.ls = ls)) { * or drop ACLs. For allow ACLs, the connection must also be committed * to conntrack so we set REGBIT_ACL_HINT_ALLOW_NEW. */ - Flow(ls._uuid, stage, 7, "ct.new && !ct.est", + Flow(ls_uuid, stage, 7, "ct.new && !ct.est", "${rEGBIT_ACL_HINT_ALLOW_NEW()} = 1; " "${rEGBIT_ACL_HINT_DROP()} = 1; " "next;", map_empty()); @@ -2455,13 +2457,13 @@ for (sw in &Switch(.ls = ls)) { * REGBIT_ACL_HINT_ALLOW_NEW. * - drop ACLs. */ - Flow(ls._uuid, stage, 6, "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1", + Flow(ls_uuid, stage, 6, "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 1", "${rEGBIT_ACL_HINT_ALLOW_NEW()} = 1; " "${rEGBIT_ACL_HINT_DROP()} = 1; " "next;", map_empty()); /* Not tracked traffic can either be allowed or dropped. */ - Flow(ls._uuid, stage, 5, "!ct.trk", + Flow(ls_uuid, stage, 5, "!ct.trk", "${rEGBIT_ACL_HINT_ALLOW()} = 1; " "${rEGBIT_ACL_HINT_DROP()} = 1; " "next;", map_empty()); @@ -2474,7 +2476,7 @@ for (sw in &Switch(.ls = ls)) { * connection must be committed with ct_label.blocked set so we set * REGBIT_ACL_HINT_BLOCK. */ - Flow(ls._uuid, stage, 4, "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0", + Flow(ls_uuid, stage, 4, "!ct.new && ct.est && !ct.rpl && ct_label.blocked == 0", "${rEGBIT_ACL_HINT_ALLOW()} = 1; " "${rEGBIT_ACL_HINT_BLOCK()} = 1; " "next;", map_empty()); @@ -2482,10 +2484,10 @@ for (sw in &Switch(.ls = ls)) { /* Not established or established and already blocked connections may * hit drop ACLs. */ - Flow(ls._uuid, stage, 3, "!ct.est", + Flow(ls_uuid, stage, 3, "!ct.est", "${rEGBIT_ACL_HINT_DROP()} = 1; " "next;", map_empty()); - Flow(ls._uuid, stage, 2, "ct.est && ct_label.blocked == 1", + Flow(ls_uuid, stage, 2, "ct.est && ct_label.blocked == 1", "${rEGBIT_ACL_HINT_DROP()} = 1; " "next;", map_empty()); @@ -2493,14 +2495,14 @@ for (sw in &Switch(.ls = ls)) { * drop ACLs in which case the connection must be committed with * ct_label.blocked set. */ - Flow(ls._uuid, stage, 1, "ct.est && ct_label.blocked == 0", + Flow(ls_uuid, stage, 1, "ct.est && ct_label.blocked == 0", "${rEGBIT_ACL_HINT_BLOCK()} = 1; " "next;", map_empty()) } } /* Ingress or Egress ACL Table (Various priorities). */ -for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_meter)) { +for (&SwitchACL(.sw = sw, .acl = &acl, .has_fair_meter = fair_meter)) { /* consider_acl */ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in var ingress = acl.direction == "from-lport" in @@ -2515,7 +2517,7 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_ * may and then its return traffic would not have an * associated conntrack entry and would return "+invalid". */ if (not has_stateful) { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = acl.priority + oVN_ACL_PRI_OFFSET(), .__match = acl.__match, @@ -2534,7 +2536,7 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_ * by ct_commit in the "stateful" stage) to indicate that the * connection should be allowed to resume. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = acl.priority + oVN_ACL_PRI_OFFSET(), .__match = "${rEGBIT_ACL_HINT_ALLOW_NEW()} == 1 && (${acl.__match})", @@ -2547,7 +2549,7 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_ * proceed to the next table. We use this to ensure that this * connection is still allowed by the currently defined * policy. Match untracked packets too. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = acl.priority + oVN_ACL_PRI_OFFSET(), .__match = "${rEGBIT_ACL_HINT_ALLOW()} == 1 && (${acl.__match})", @@ -2564,9 +2566,9 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_ * connection, then we can simply reject/drop it. */ var __match = "${rEGBIT_ACL_HINT_DROP()} == 1" in if (acl.action == "reject") { - Reject(ls._uuid, pipeline, stage, acl, fair_meter, __match, "") + Reject(sw._uuid, pipeline, stage, acl, fair_meter, __match, "") } else { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = acl.priority + oVN_ACL_PRI_OFFSET(), .__match = __match ++ " && (${acl.__match})", @@ -2587,9 +2589,9 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_ var __match = "${rEGBIT_ACL_HINT_BLOCK()} == 1" in var actions = "ct_commit { ct_label.blocked = 1; }; " in if (acl.action == "reject") { - Reject(ls._uuid, pipeline, stage, acl, fair_meter, __match, actions) + Reject(sw._uuid, pipeline, stage, acl, fair_meter, __match, actions) } else { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = acl.priority + oVN_ACL_PRI_OFFSET(), .__match = __match ++ " && (${acl.__match})", @@ -2601,9 +2603,9 @@ for (&SwitchACL(.sw = sw@&Switch{.ls = ls}, .acl = &acl, .has_fair_meter = fair_ * so a "reject/drop" ACL is simply the "reject/drop" * logical flow action in all cases. */ if (acl.action == "reject") { - Reject(ls._uuid, pipeline, stage, acl, fair_meter, "", "") + Reject(sw._uuid, pipeline, stage, acl, fair_meter, "", "") } else { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = acl.priority + oVN_ACL_PRI_OFFSET(), .__match = acl.__match, @@ -2623,7 +2625,7 @@ for (SwitchPortDHCPv4Options(.port = &SwitchPort{.lsp = lsp, .sw = &sw}, (Some{var server_id}, Some{var server_mac}, Some{var lease_time}) = (options.get("server_id"), options.get("server_mac"), options.get("lease_time")) in var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 34000, .__match = "outport == ${json_string_escape(lsp.name)} " @@ -2643,7 +2645,7 @@ for (SwitchPortDHCPv6Options(.port = &SwitchPort{.lsp = lsp, .sw = &sw}, /* Get the link local IP of the DHCPv6 server from the * server MAC. */ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_ACL(), .priority = 34000, .__match = "outport == ${json_string_escape(lsp.name)} " @@ -2662,26 +2664,26 @@ QoSAction(qos, k, v) :- (var k, var v) = action. /* QoS rules */ -for (&Switch(.ls = ls)) { - Flow(.logical_datapath = ls._uuid, +for (&Switch(._uuid = ls_uuid)) { + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_QOS_MARK(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_QOS_MARK(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_QOS_METER(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_QOS_METER(), .priority = 0, .__match = "1", @@ -2696,7 +2698,7 @@ for (SwitchQoS(.sw = &sw, .qos = &qos)) { /* FIXME: Can value_action be negative? */ for (QoSAction(qos._uuid, key_action, value_action)) { if (key_action == "dscp") { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = qos.priority, .__match = qos.__match, @@ -2730,7 +2732,7 @@ for (SwitchQoS(.sw = &sw, .qos = &qos)) { * * We limit the bandwidth of this flow by adding a meter table. */ - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = stage, .priority = qos.priority, .__match = qos.__match, @@ -2741,33 +2743,33 @@ for (SwitchQoS(.sw = &sw, .qos = &qos)) { } /* LB rules */ -for (&Switch(.ls = ls, .has_lb_vip = has_lb_vip)) { +for (&Switch(._uuid = ls_uuid, .load_balancer = load_balancer, .has_lb_vip = has_lb_vip)) { /* Ingress and Egress LB Table (Priority 0): Packets are allowed by * default. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_LB(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_LB(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - if (not ls.load_balancer.is_empty()) { + if (not load_balancer.is_empty()) { for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "router"}, .json_name = lsp_name, - .sw = &Switch{.ls = ls})) { - Flow(.logical_datapath = ls._uuid, + .sw = &Switch{._uuid = ls_uuid})) { + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_LB(), .priority = 65535, .__match = "ip && inport == ${lsp_name}", .actions = "next;", .external_ids = stage_hint(lsp._uuid)); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_LB(), .priority = 65535, .__match = "ip && outport == ${lsp_name}", @@ -2780,13 +2782,13 @@ for (&Switch(.ls = ls, .has_lb_vip = has_lb_vip)) { /* Ingress and Egress LB Table (Priority 65534). * * Send established traffic through conntrack for just NAT. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_LB(), .priority = 65534, .__match = "ct.est && !ct.rel && !ct.new && !ct.inv && ct_label.natted == 1", .actions = "${rEGBIT_CONNTRACK_NAT()} = 1; next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_LB(), .priority = 65534, .__match = "ct.est && !ct.rel && !ct.new && !ct.inv && ct_label.natted == 1", @@ -2800,16 +2802,16 @@ relation LbProtocol[string] LbProtocol["tcp"]. LbProtocol["udp"]. LbProtocol["sctp"]. -for (&Switch(.ls = ls)) { +for (&Switch(._uuid = ls_uuid)) { /* Ingress and Egress stateful Table (Priority 0): Packets are * allowed by default. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_STATEFUL(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_STATEFUL(), .priority = 0, .__match = "1", @@ -2820,13 +2822,13 @@ for (&Switch(.ls = ls)) { * committed to conntrack. We always set ct_label.blocked to 0 here as * any packet that makes it this far is part of a connection we * want to allow to continue. */ - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_STATEFUL(), .priority = 100, .__match = "${rEGBIT_CONNTRACK_COMMIT()} == 1", .actions = "ct_commit { ct_label.blocked = 0; }; next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_STATEFUL(), .priority = 100, .__match = "${rEGBIT_CONNTRACK_COMMIT()} == 1", @@ -2844,14 +2846,14 @@ for (&Switch(.ls = ls)) { * transport port to be used when detecting hairpin packets. */ for (LbProtocol[protocol]) { - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_STATEFUL(), .priority = 100, .__match = "${rEGBIT_CONNTRACK_NAT()} == 1 && ip4 && ${protocol}", .actions = "${rEG_ORIG_DIP_IPV4()} = ip4.dst; " "${rEG_ORIG_TP_DPORT()} = ${protocol}.dst; ct_lb;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_STATEFUL(), .priority = 100, .__match = "${rEGBIT_CONNTRACK_NAT()} == 1 && ip6 && ${protocol}", @@ -2860,7 +2862,7 @@ for (&Switch(.ls = ls)) { .external_ids = map_empty()) }; - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_STATEFUL(), .priority = 100, .__match = "${rEGBIT_CONNTRACK_NAT()} == 1", @@ -2941,7 +2943,7 @@ function build_lb_vip_actions(lbvip: Ref, lbvip.lb.protocol); actions0 ++ actions } -Flow(.logical_datapath = sw.ls._uuid, +Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_STATEFUL(), .priority = priority, .__match = __match, @@ -2949,7 +2951,7 @@ Flow(.logical_datapath = sw.ls._uuid, .external_ids = stage_hint(lb._uuid)) :- sw in &Switch(), LBVIPWithStatus[lbvip@&LBVIPWithStatus{.lb = lb}], - sw.ls.load_balancer.contains(lb._uuid), + sw.load_balancer.contains(lb._uuid), var priority = if (lbvip.vip_port != 0) { 120 } else { 110 }, var actions = { /* Store the original destination IP to be used when generating @@ -2982,12 +2984,12 @@ Flow(.logical_datapath = ls_uuid, .__match = "1", .actions = "next;", .external_ids = map_empty()) :- - &Switch(.ls = nb::Logical_Switch{._uuid = ls_uuid}), + &Switch(._uuid = ls_uuid), var stages = [s_SWITCH_IN_PRE_HAIRPIN(), s_SWITCH_IN_NAT_HAIRPIN(), s_SWITCH_IN_HAIRPIN()], var stage = FlatMap(stages). -for (&Switch(.ls = nb::Logical_Switch{._uuid = ls_uuid}, .has_lb_vip = true)) { +for (&Switch(._uuid = ls_uuid, .has_lb_vip = true)) { /* Check if the packet needs to be hairpinned. * Set REGBIT_HAIRPIN in the original direction and * REGBIT_HAIRPIN_REPLY in the reply direction. @@ -3055,7 +3057,7 @@ for (&SwitchPort(.lsp = lsp, .sw = &sw, .json_name = json_name, .ps_eth_addresse None -> "next;", Some{id} -> "set_queue(${id}); next;" } in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_L2(), .priority = 50, .__match = __match, @@ -3090,7 +3092,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) " && ip4.src == 0.0.0.0" " && ip4.dst == 255.255.255.255" " && udp.src == 68 && udp.dst == 67" in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_IP(), .priority = 90, .__match = dhcp_match, @@ -3113,7 +3115,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) "inport == ${port.json_name} && eth.src == ${ps.ea} && ip4.src == {" ++ addrs.join(", ") ++ "}" in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_IP(), .priority = 90, .__match = __match, @@ -3128,7 +3130,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) " && ip6.dst == ff02::/16" " && icmp6.type == {131, 135, 143}" in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_IP(), .priority = 90, .__match = dad_match, @@ -3138,7 +3140,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) var __match = "inport == ${port.json_name} && eth.src == ${ps.ea}" ++ build_port_security_ipv6_flow(Ingress, ps.ea, ps.ipv6_addrs) in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_IP(), .priority = 90, .__match = __match, @@ -3148,7 +3150,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) }; var __match = "inport == ${port.json_name} && eth.src == ${ps.ea} && ip" in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_IP(), .priority = 80, .__match = __match, @@ -3196,7 +3198,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) prefix } } in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_ND(), .priority = 90, .__match = __match, @@ -3208,7 +3210,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) var __match = "inport == ${port.json_name} && eth.src == ${ps.ea}" ++ build_port_security_ipv6_nd_flow(ps.ea, ps.ipv6_addrs) in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_ND(), .priority = 90, .__match = __match, @@ -3216,7 +3218,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) .external_ids = stage_hint(port.lsp._uuid)) } }; - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_PORT_SEC_ND(), .priority = 80, .__match = "inport == ${port.json_name} && (arp || nd)", @@ -3227,14 +3229,14 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) /* Ingress table PORT_SEC_ND and PORT_SEC_IP: Port security - IP and ND, by * default goto next. (priority 0)*/ -for (&Switch(.ls = ls)) { - Flow(.logical_datapath = ls._uuid, +for (&Switch(._uuid = ls_uuid)) { + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PORT_SEC_ND(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PORT_SEC_IP(), .priority = 0, .__match = "1", @@ -3249,7 +3251,7 @@ for (&SwitchPort(.lsp = lsp, .sw = &sw, .json_name = json_name) if lsp.is_enabled() and (lsp.__type == "localnet" or lsp.__type == "vtep")) { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 100, .__match = "inport == ${json_name}", @@ -3270,7 +3272,7 @@ function lsp_is_up(lsp: nb::Logical_Switch_Port): bool = { * - ARP reply from the virtual ip which belongs to a logical * port of type 'virtual' and bind that port. * */ - Flow(.logical_datapath = sp.sw.ls._uuid, + Flow(.logical_datapath = sp.sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 100, .__match = "inport == ${vp.json_name} && " @@ -3313,7 +3315,7 @@ for (CheckLspIsUp[check_lsp_is_up]) { "outport = inport; " "flags.loopback = 1; " "output;" in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 50, .__match = __match, @@ -3332,7 +3334,7 @@ for (CheckLspIsUp[check_lsp_is_up]) { * detect situations where the network is not working as * configured, so dropping the request would frustrate that * intent.) */ - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 100, .__match = __match ++ " && inport == ${json_name}", @@ -3362,7 +3364,7 @@ for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = lsp, .json_name = json_nam "output; " "};" in { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 50, .__match = __match, @@ -3371,7 +3373,7 @@ for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = lsp, .json_name = json_nam /* Do not reply to a solicitation from the port that owns the * address (otherwise DAD detection will fail). */ - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 100, .__match = __match ++ " && inport == ${json_name}", @@ -3393,7 +3395,7 @@ for (ls in nb::Logical_Switch) { /* Ingress table ARP_ND_RSP: ARP/ND responder for service monitor source ip. * (priority 110)*/ -Flow(.logical_datapath = sp.sw.ls._uuid, +Flow(.logical_datapath = sp.sw._uuid, .stage = s_SWITCH_IN_ARP_ND_RSP(), .priority = 110, .__match = "arp.tpa == ${svc_mon_src_ip} && arp.op == 1", @@ -3775,7 +3777,7 @@ for (ls in nb::Logical_Switch) { .external_ids = map_empty()) } -Flow(.logical_datapath = sw.ls._uuid, +Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 110, .__match = "eth.dst == $svc_monitor_mac", @@ -3783,7 +3785,7 @@ Flow(.logical_datapath = sw.ls._uuid, .external_ids = map_empty()) :- sw in &Switch(). -for (sw in &Switch(.ls = ls, .mcast_cfg = &mcast_cfg) +for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = &mcast_cfg) if (mcast_cfg.enabled)) { for (SwitchMcastFloodRelayPorts(sw, relay_ports)) { for (SwitchMcastFloodReportPorts(sw, flood_report_ports)) { @@ -3803,7 +3805,7 @@ for (sw in &Switch(.ls = ls, .mcast_cfg = &mcast_cfg) } } in { /* Punt IGMP traffic to controller. */ - UniqueFlow[Flow{.logical_datapath = ls._uuid, + UniqueFlow[Flow{.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 100, .__match = "ip4 && ip.proto == 2", @@ -3811,7 +3813,7 @@ for (sw in &Switch(.ls = ls, .mcast_cfg = &mcast_cfg) .external_ids = map_empty()}]; /* Punt MLD traffic to controller. */ - UniqueFlow[Flow{.logical_datapath = ls._uuid, + UniqueFlow[Flow{.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 100, .__match = "mldv1 || mldv2", @@ -3822,7 +3824,7 @@ for (sw in &Switch(.ls = ls, .mcast_cfg = &mcast_cfg) * all ports - RFC 4541, section 2.1.2, item 2. */ var flood = json_string_escape(mC_FLOOD().0) in - UniqueFlow[Flow{.logical_datapath = ls._uuid, + UniqueFlow[Flow{.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 85, .__match = "ip4.mcast && ip4.dst == 224.0.0.0/24", @@ -3833,7 +3835,7 @@ for (sw in &Switch(.ls = ls, .mcast_cfg = &mcast_cfg) * multicast IPs (RFC 4291, 2.7.1). */ var flood = json_string_escape(mC_FLOOD().0) in - UniqueFlow[Flow{.logical_datapath = ls._uuid, + UniqueFlow[Flow{.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 85, .__match = "ip6.mcast_flood", @@ -3872,7 +3874,7 @@ for (sw in &Switch(.ls = ls, .mcast_cfg = &mcast_cfg) "" } } in - UniqueFlow[Flow{.logical_datapath = ls._uuid, + UniqueFlow[Flow{.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 80, .__match = "ip4.mcast || ip6.mcast", @@ -3926,7 +3928,7 @@ for (IgmpSwitchMulticastGroup(.address = address, .switch = &sw)) { "" } } in - UniqueFlow[Flow{.logical_datapath = sw.ls._uuid, + UniqueFlow[Flow{.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 90, .__match = "eth.mcast && ${ipX} && ${ipX}.dst == ${address}", @@ -3946,7 +3948,7 @@ for (IgmpSwitchMulticastGroup(.address = address, .switch = &sw)) { * chassis, drop ARP requests arriving on localnet ports from X's Ethernet * address, if the ARP request is asking to translate the IP address of a * router port on LS. */ -Flow(.logical_datapath = sp.sw.ls._uuid, +Flow(.logical_datapath = sp.sw._uuid, .stage = s_SWITCH_IN_EXTERNAL_PORT(), .priority = 100, .__match = ("inport == ${json_string_escape(localnet_port.1)} && " @@ -3962,7 +3964,7 @@ Flow(.logical_datapath = sp.sw.ls._uuid, rp in &SwitchPort(.sw = sp.sw), rp.lsp.__type == "router", SwitchPortIPv4Address(.port = rp, .addr = rp_addr). -Flow(.logical_datapath = sp.sw.ls._uuid, +Flow(.logical_datapath = sp.sw._uuid, .stage = s_SWITCH_IN_EXTERNAL_PORT(), .priority = 100, .__match = ("inport == ${json_string_escape(localnet_port.1)} && " @@ -3979,7 +3981,7 @@ Flow(.logical_datapath = sp.sw.ls._uuid, rp in &SwitchPort(.sw = sp.sw), rp.lsp.__type == "router", SwitchPortIPv6Address(.port = rp, .addr = rp_addr). -Flow(.logical_datapath = sp.sw.ls._uuid, +Flow(.logical_datapath = sp.sw._uuid, .stage = s_SWITCH_IN_EXTERNAL_PORT(), .priority = 100, .__match = ("inport == ${json_string_escape(localnet_port.1)} && " @@ -4013,7 +4015,7 @@ for (ls in nb::Logical_Switch) { for (SwitchPortStaticAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = &sw}, .addrs = addrs) if lsp.__type != "external") { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 50, .__match = "eth.dst == ${addrs.ea}", @@ -4054,7 +4056,7 @@ function lrouter_port_ip_reachable(rp: Ref, addr: v46_ip): bool { }; false } -UniqueFlow[Flow{.logical_datapath = sw.ls._uuid, +UniqueFlow[Flow{.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 75, .__match = __match, @@ -4142,7 +4144,7 @@ function get_arp_forward_ips(rp: Ref): (Set, Set) = * delivers to patch ports) but we're bypassing multicast_groups. * (This is why we match against fLAGBIT_NOT_VXLAN() here.) */ -AnnotatedFlow(.f = Flow{.logical_datapath = sw.ls._uuid, +AnnotatedFlow(.f = Flow{.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 80, .__match = fLAGBIT_NOT_VXLAN() ++ @@ -4161,7 +4163,7 @@ AnnotatedFlow(.f = Flow{.logical_datapath = sw.ls._uuid, (var all_ips_v4, _) = get_arp_forward_ips(rp), not all_ips_v4.is_empty(), var mc_flood_l2 = json_string_escape(mC_FLOOD_L2().0). -AnnotatedFlow(.f = Flow{.logical_datapath = sw.ls._uuid, +AnnotatedFlow(.f = Flow{.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 80, .__match = fLAGBIT_NOT_VXLAN() ++ @@ -4184,7 +4186,7 @@ AnnotatedFlow(.f = Flow{.logical_datapath = sw.ls._uuid, for (SwitchPortNewDynamicAddress(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = &sw}, .address = Some{addrs}) if lsp.__type != "external") { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 50, .__match = "eth.dst == ${addrs.ea}", @@ -4225,7 +4227,7 @@ for (&SwitchPort(.lsp = lsp, } else { "eth.dst == ${mac}" } in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 50, .__match = __match, @@ -4241,7 +4243,7 @@ for (&SwitchPort(.lsp = lsp, Some{var emac} = nat.nat.external_mac in Some{var nat_mac} = eth_addr_from_string(emac) in var __match = "eth.dst == ${nat_mac} && is_chassis_resident(${json_string_escape(lport)})" in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 50, .__match = __match, @@ -4262,7 +4264,7 @@ for (&SwitchPort(.lsp = lsp, }*/ /* Ingress table L2_LKUP and L2_UNKNOWN: Destination lookup for unknown MACs (priority 0). */ -for (sw in &Switch(.ls = nb::Logical_Switch{._uuid = ls_uuid})) { +for (sw in &Switch(._uuid = ls_uuid)) { Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_L2_LKUP(), .priority = 0, @@ -4292,14 +4294,14 @@ for (sw in &Switch(.ls = nb::Logical_Switch{._uuid = ls_uuid})) { /* Egress tables PORT_SEC_IP: Egress port security - IP (priority 0) * Egress table PORT_SEC_L2: Egress port security L2 - multicast/broadcast (priority 100). */ -for (&Switch(.ls = ls)) { - Flow(.logical_datapath = ls._uuid, +for (&Switch(._uuid = ls_uuid)) { + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PORT_SEC_IP(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()); - Flow(.logical_datapath = ls._uuid, + Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_OUT_PORT_SEC_L2(), .priority = 100, .__match = "eth.mcast", @@ -4323,19 +4325,19 @@ Flow(.logical_datapath = ls_uuid, sp in &SwitchPort(.lsp = nb::Logical_Switch_Port{._uuid = lsp_uuid, .__type = ""}, .ps_addresses = vec_empty()). -Flow(.logical_datapath = ls._uuid, +Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_LOOKUP_FDB(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()), -Flow(.logical_datapath = ls._uuid, +Flow(.logical_datapath = ls_uuid, .stage = s_SWITCH_IN_PUT_FDB(), .priority = 0, .__match = "1", .actions = "next;", .external_ids = map_empty()) :- - &Switch(.ls = ls). + &Switch(._uuid = ls_uuid). /* Egress table PORT_SEC_IP: Egress port security - IP (priorities 90 and 80) * if port security enabled. @@ -4346,7 +4348,7 @@ Flow(.logical_datapath = ls._uuid, * * Priority 150 rules drop packets to disabled logical ports, so that they * don't even receive multicast or broadcast packets. */ -Flow(.logical_datapath = sw.ls._uuid, +Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_PORT_SEC_L2(), .priority = 50, .__match = __match, @@ -4369,7 +4371,7 @@ Flow(.logical_datapath = sw.ls._uuid, for (&SwitchPort(.lsp = lsp, .json_name = json_name, .sw = &sw) if not lsp.is_enabled() and lsp.__type != "external") { - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_PORT_SEC_L2(), .priority = 150, .__match = "outport == {$json_name}", @@ -4401,7 +4403,7 @@ for (SwitchPortPSAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_nam var __match = "outport == ${json_name} && eth.dst == ${ps.ea} && ip4.dst == {255.255.255.255, 224.0.0.0/4, " ++ addrs.join(", ") ++ "}" in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_PORT_SEC_IP(), .priority = 90, .__match = __match, @@ -4411,7 +4413,7 @@ for (SwitchPortPSAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_nam if (ps.ipv6_addrs.len() > 0) { var __match = "outport == ${json_name} && eth.dst == ${ps.ea}" ++ build_port_security_ipv6_flow(Egress, ps.ea, ps.ipv6_addrs) in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_PORT_SEC_IP(), .priority = 90, .__match = __match, @@ -4419,7 +4421,7 @@ for (SwitchPortPSAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_nam .external_ids = stage_hint(lsp._uuid)) }; var __match = "outport == ${json_name} && eth.dst == ${ps.ea} && ip" in - Flow(.logical_datapath = sw.ls._uuid, + Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_PORT_SEC_IP(), .priority = 80, .__match = __match, @@ -6920,12 +6922,12 @@ Flow(.logical_datapath = lr_uuid, * connects) and if the address in question is reachable from the * router port, add an ARP/ND entry in that router's pipeline. */ for (SwitchPortIPv4Address( - .port = &SwitchPort{.lsp = lsp, .sw = &sw}, + .port = &SwitchPort{.lsp = lsp, .sw = sw}, .ea = ea, .addr = addr) if lsp.__type != "router" and lsp.__type != "virtual" and lsp.is_enabled()) { - for (&SwitchPort(.sw = &Switch{.ls = nb::Logical_Switch{._uuid = sw.ls._uuid}}, + for (&SwitchPort(.sw = &Switch{._uuid = sw._uuid}, .peer = Some{&peer@RouterPort{.router = &peer_router}})) { Some{_} = find_lrp_member_ip(peer.networks, IPv4{addr.addr}) in @@ -6940,12 +6942,12 @@ for (SwitchPortIPv4Address( } for (SwitchPortIPv6Address( - .port = &SwitchPort{.lsp = lsp, .sw = &sw}, + .port = &SwitchPort{.lsp = lsp, .sw = sw}, .ea = ea, .addr = addr) if lsp.__type != "router" and lsp.__type != "virtual" and lsp.is_enabled()) { - for (&SwitchPort(.sw = &Switch{.ls = nb::Logical_Switch{._uuid = sw.ls._uuid}}, + for (&SwitchPort(.sw = &Switch{._uuid = sw._uuid}, .peer = Some{&peer@RouterPort{.router = &peer_router}})) { Some{_} = find_lrp_member_ip(peer.networks, IPv6{addr.addr}) in @@ -7021,12 +7023,12 @@ Flow(.logical_datapath = peer.router._uuid, * the switch in question. */ for (&SwitchPort(.lsp = lsp1, .peer = Some{&peer1@RouterPort{.router = &peer_router}}, - .sw = &sw) + .sw = sw) if lsp1.is_enabled() and not peer_router.options.get_bool_def("dynamic_neigh_routers", false)) { for (&SwitchPort(.lsp = lsp2, .peer = Some{&peer2}, - .sw = &Switch{.ls = nb::Logical_Switch{._uuid = sw.ls._uuid}}) + .sw = &Switch{._uuid = sw._uuid}) /* Skip the router port under consideration. */ if peer2.lrp._uuid != peer1.lrp._uuid) { @@ -7425,7 +7427,7 @@ function get_port_tunkey(map: Map, key: string): Option relation RequestedPortTunKey(datapath: uuid, port: uuid, tunkey: integer) RequestedPortTunKey(datapath, port, tunkey) :- sp in &SwitchPort(), - var datapath = sp.sw.ls._uuid, + var datapath = sp.sw._uuid, var port = sp.lsp._uuid, Some{var tunkey} = get_port_tunkey(sp.lsp.options, "requested-tnl-key"). RequestedPortTunKey(datapath, port, tunkey) :- From patchwork Sat Mar 27 00:31:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459079 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fvV2Xtqz9sCD for ; Sat, 27 Mar 2021 11:33:10 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 1466184E7A; Sat, 27 Mar 2021 00:33:08 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id q_J-oBqH-2lQ; Sat, 27 Mar 2021 00:33:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTP id 72A9E84E32; Sat, 27 Mar 2021 00:32:41 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4A116C001E; Sat, 27 Mar 2021 00:32:39 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 627B6C0018 for ; Sat, 27 Mar 2021 00:32:36 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id A0D1E84DA4 for ; Sat, 27 Mar 2021 00:32:29 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 3rPXYO96r9VJ for ; Sat, 27 Mar 2021 00:32:27 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id 48FB084DC9 for ; Sat, 27 Mar 2021 00:32:17 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 591E9FF803; Sat, 27 Mar 2021 00:32:14 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:38 -0700 Message-Id: <20210327003147.2955790-13-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 12/21] ovn-northd-ddlog: Intern the SwitchPort table. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Change the type of record in the `SwitchPort` table from `Ref` to `Intern`. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/ipam.dl | 22 +++++++-------- northd/lswitch.dl | 64 +++++++++++++++++++++++--------------------- northd/ovn_northd.dl | 2 +- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/northd/ipam.dl b/northd/ipam.dl index e7373f250a7f..40d542ec0687 100644 --- a/northd/ipam.dl +++ b/northd/ipam.dl @@ -212,7 +212,7 @@ SwitchPortAllocatedIPv4DynAddress(lsport, dyn_addr) :- Some{port0} -> { match (port0.sw.subnet) { None -> { - abort("needs_dynamic_ipv4address is true, but subnet is undefined in port ${uuid2str(deref(port0).lsp._uuid)}"); + abort("needs_dynamic_ipv4address is true, but subnet is undefined in port ${uuid2str(port0.lsp._uuid)}"); (0, 0) }, Some{(_, _, start_ipv4, total_ipv4s)} -> (start_ipv4, total_ipv4s) @@ -220,27 +220,27 @@ SwitchPortAllocatedIPv4DynAddress(lsport, dyn_addr) :- } }; for (port in ports) { - //warn("port(${deref(port).lsp._uuid})"); - match (deref(port).dynamic_address) { + //warn("port(${port.lsp._uuid})"); + match (port.dynamic_address) { None -> { /* no dynamic address yet -- allocate one now */ - //warn("need_addr(${deref(port).lsp._uuid})"); - need_addr.push(deref(port).lsp._uuid) + //warn("need_addr(${port.lsp._uuid})"); + need_addr.push(port.lsp._uuid) }, Some{dynaddr} -> { match (dynaddr.ipv4_addrs.nth(0)) { None -> { /* dynamic address does not have IPv4 component -- allocate one now */ - //warn("need_addr(${deref(port).lsp._uuid})"); - need_addr.push(deref(port).lsp._uuid) + //warn("need_addr(${port.lsp._uuid})"); + need_addr.push(port.lsp._uuid) }, Some{addr} -> { var haddr = addr.addr.a; if (haddr < start_ipv4 or haddr >= start_ipv4 + total_ipv4s) { - need_addr.push(deref(port).lsp._uuid) + need_addr.push(port.lsp._uuid) } else if (used_addrs.contains(haddr)) { - need_addr.push(deref(port).lsp._uuid); - warn("Duplicate IP set on switch ${deref(port).lsp.name}: ${addr.addr}") + need_addr.push(port.lsp._uuid); + warn("Duplicate IP set on switch ${port.lsp.name}: ${addr.addr}") } else { /* has valid dynamic address -- record it in used_addrs */ used_addrs.insert(haddr); @@ -459,7 +459,7 @@ SwitchPortNewMACDynAddress(lsp._uuid, addr) :- * Dynamic IPv6 address allocation. * `needs_dynamic_ipv6address` -> mac.to_ipv6_eui64(ipv6_prefix) */ -relation SwitchPortNewDynamicAddress(port: Ref, address: Option) +relation SwitchPortNewDynamicAddress(port: Intern, address: Option) SwitchPortNewDynamicAddress(port, None) :- port in &SwitchPort(.lsp = lsp), diff --git a/northd/lswitch.dl b/northd/lswitch.dl index 25abd0aa8189..c089fadac863 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -25,7 +25,7 @@ import vec function is_enabled(lsp: nb::Logical_Switch_Port): bool { is_enabled(lsp.enabled) } function is_enabled(lsp: Ref): bool { lsp.deref().is_enabled() } function is_enabled(sp: SwitchPort): bool { sp.lsp.is_enabled() } -function is_enabled(sp: Ref): bool { sp.lsp.is_enabled() } +function is_enabled(sp: Intern): bool { sp.lsp.is_enabled() } relation SwitchRouterPeerRef(lsp: uuid, rport: Option>) @@ -445,7 +445,7 @@ LBVIPBackendStatus(lbvip, backend, true) :- /* SwitchPortDHCPv4Options: many-to-one relation between logical switches and DHCPv4 options */ relation SwitchPortDHCPv4Options( - port: Ref, + port: Intern, dhcpv4_options: Ref) SwitchPortDHCPv4Options(port, options) :- @@ -456,7 +456,7 @@ SwitchPortDHCPv4Options(port, options) :- /* SwitchPortDHCPv6Options: many-to-one relation between logical switches and DHCPv4 options */ relation SwitchPortDHCPv6Options( - port: Ref, + port: Intern, dhcpv6_options: Ref) SwitchPortDHCPv6Options(port, options) :- @@ -551,7 +551,7 @@ SwitchPortHAChassisGroup(lsp_uuid, None) :- * - `up` - true if the port is bound to a chassis or has type "" * - 'hac_group_uuid' - uuid of sb::HA_Chassis_Group, only for "external" ports */ -relation &SwitchPort( +typedef SwitchPort = SwitchPort { lsp: nb::Logical_Switch_Port, json_name: string, sw: Intern, @@ -571,27 +571,31 @@ relation &SwitchPort( up: bool, mcast_cfg: Ref, hac_group_uuid: Option -) - -&SwitchPort(.lsp = lsp, - .json_name = json_string_escape(lsp.name), - .sw = sw, - .peer = peer, - .static_addresses = static_addresses, - .dynamic_address = dynamic_address, - .static_dynamic_mac = static_dynamic_mac, - .static_dynamic_ipv4 = static_dynamic_ipv4, - .static_dynamic_ipv6 = static_dynamic_ipv6, - .ps_addresses = ps_addresses, - .ps_eth_addresses = ps_eth_addresses, - .parent_name = parent_name, - .needs_dynamic_ipv4address = needs_dynamic_ipv4address, - .needs_dynamic_macaddress = needs_dynamic_macaddress, - .needs_dynamic_ipv6address = needs_dynamic_ipv6address, - .needs_dynamic_tag = needs_dynamic_tag, - .up = up, - .mcast_cfg = mcast_cfg, - .hac_group_uuid = hac_group_uuid) :- +} + +relation SwitchPort[Intern] + +SwitchPort[SwitchPort{ + .lsp = lsp, + .json_name = json_string_escape(lsp.name), + .sw = sw, + .peer = peer, + .static_addresses = static_addresses, + .dynamic_address = dynamic_address, + .static_dynamic_mac = static_dynamic_mac, + .static_dynamic_ipv4 = static_dynamic_ipv4, + .static_dynamic_ipv6 = static_dynamic_ipv6, + .ps_addresses = ps_addresses, + .ps_eth_addresses = ps_eth_addresses, + .parent_name = parent_name, + .needs_dynamic_ipv4address = needs_dynamic_ipv4address, + .needs_dynamic_macaddress = needs_dynamic_macaddress, + .needs_dynamic_ipv6address = needs_dynamic_ipv6address, + .needs_dynamic_tag = needs_dynamic_tag, + .up = up, + .mcast_cfg = mcast_cfg, + .hac_group_uuid = hac_group_uuid + }.intern()] :- nb::Logical_Switch_Port[lsp], LogicalSwitchPort(lsp._uuid, lswitch_uuid), sw in &Switch(._uuid = lswitch_uuid, @@ -667,7 +671,7 @@ relation &SwitchPort( .hac_group_uuid = hac_group_uuid). /* Switch port port security addresses */ -relation SwitchPortPSAddresses(port: Ref, +relation SwitchPortPSAddresses(port: Intern, ps_addrs: lport_addresses) SwitchPortPSAddresses(port, ps_addrs) :- @@ -676,7 +680,7 @@ SwitchPortPSAddresses(port, ps_addrs) :- /* All static addresses associated with a port parsed into * the lport_addresses data structure */ -relation SwitchPortStaticAddresses(port: Ref, +relation SwitchPortStaticAddresses(port: Intern, addrs: lport_addresses) SwitchPortStaticAddresses(port, addrs) :- port in &SwitchPort(.static_addresses = static_addresses), @@ -684,7 +688,7 @@ SwitchPortStaticAddresses(port, addrs) :- /* All static and dynamic addresses associated with a port parsed into * the lport_addresses data structure */ -relation SwitchPortAddresses(port: Ref, +relation SwitchPortAddresses(port: Intern, addrs: lport_addresses) SwitchPortAddresses(port, addrs) :- SwitchPortStaticAddresses(port, addrs). @@ -715,7 +719,7 @@ SwitchPortAddresses(port, addrs) :- }. /* All static and dynamic IPv4 addresses associated with a port */ -relation SwitchPortIPv4Address(port: Ref, +relation SwitchPortIPv4Address(port: Intern, ea: eth_addr, addr: ipv4_netaddr) @@ -724,7 +728,7 @@ SwitchPortIPv4Address(port, ea, addr) :- var addr = FlatMap(addrs). /* All static and dynamic IPv6 addresses associated with a port */ -relation SwitchPortIPv6Address(port: Ref, +relation SwitchPortIPv6Address(port: Intern, ea: eth_addr, addr: ipv6_netaddr) diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 1745adcf8949..c4d46b2a8406 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -3576,7 +3576,7 @@ function json_string_escape_vec(names: Vec): string * there's more than one localnet port since the C version uses multiple flows * in that case.) */ -function match_dhcp_input(lsp: Ref): (string, string) = +function match_dhcp_input(lsp: Intern): (string, string) = { if (lsp.lsp.__type == "external" and not lsp.sw.localnet_ports.is_empty()) { ("inport == " ++ json_string_escape_vec(lsp.sw.localnet_ports.map(|x| x.1)) ++ " && ", From patchwork Sat Mar 27 00:31:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459078 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fvS0RQHz9sCD for ; Sat, 27 Mar 2021 11:33:07 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id AA39A419A9; Sat, 27 Mar 2021 00:33:05 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 75c_9HcoIjcV; Sat, 27 Mar 2021 00:33:03 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTP id 8955441906; Sat, 27 Mar 2021 00:32:49 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 46AC5C000E; Sat, 27 Mar 2021 00:32:49 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 17B78C000A for ; Sat, 27 Mar 2021 00:32:47 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 883E141945 for ; Sat, 27 Mar 2021 00:32:30 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id hb0WJ8XKw_EN for ; Sat, 27 Mar 2021 00:32:28 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp4.osuosl.org (Postfix) with ESMTPS id 4381E418FC for ; Sat, 27 Mar 2021 00:32:18 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 03ACEFF804; Sat, 27 Mar 2021 00:32:15 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:39 -0700 Message-Id: <20210327003147.2955790-14-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 13/21] ovn-northd-ddlog: Intern the RouterPort table. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Change the type of record in the `RouterPort` table from `Ref` to `Intern`. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/lrouter.dl | 37 +++++++++++++++++++++---------------- northd/lswitch.dl | 4 ++-- northd/ovn_northd.dl | 14 +++++++------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/northd/lrouter.dl b/northd/lrouter.dl index b2b429af3c96..e4e5cbf9f212 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -23,7 +23,7 @@ import lswitch function is_enabled(lr: nb::Logical_Router): bool { is_enabled(lr.enabled) } function is_enabled(lrp: nb::Logical_Router_Port): bool { is_enabled(lrp.enabled) } function is_enabled(rp: RouterPort): bool { rp.lrp.is_enabled() } -function is_enabled(rp: Ref): bool { rp.lrp.is_enabled() } +function is_enabled(rp: Intern): bool { rp.lrp.is_enabled() } /* default logical flow prioriry for distributed routes */ function dROUTE_PRIO(): bit<32> = 400 @@ -575,7 +575,7 @@ RouterPortHasBfd(lrp_uuid, false) :- /* FIXME: what should happen when extract_lrp_networks fails? */ /* RouterPort relation collects all attributes of a logical router port */ -relation &RouterPort( +typedef RouterPort = RouterPort { lrp: nb::Logical_Router_Port, json_name: string, networks: lport_addresses, @@ -584,17 +584,22 @@ relation &RouterPort( peer: RouterPeer, mcast_cfg: Ref, sb_options: Map, - has_bfd: bool) - -&RouterPort(.lrp = lrp, - .json_name = json_string_escape(lrp.name), - .networks = networks, - .router = router, - .is_redirect = is_redirect, - .peer = peer, - .mcast_cfg = mcast_cfg, - .sb_options = sb_options, - .has_bfd = has_bfd) :- + has_bfd: bool +} + +relation RouterPort[Intern] + +RouterPort[RouterPort{ + .lrp = lrp, + .json_name = json_string_escape(lrp.name), + .networks = networks, + .router = router, + .is_redirect = is_redirect, + .peer = peer, + .mcast_cfg = mcast_cfg, + .sb_options = sb_options, + .has_bfd = has_bfd + }.intern()] :- nb::Logical_Router_Port[lrp], Some{var networks} = extract_lrp_networks(lrp.mac, lrp.networks), LogicalRouterPort(lrp._uuid, lrouter_uuid), @@ -605,13 +610,13 @@ relation &RouterPort( RouterPortSbOptions(lrp._uuid, sb_options), RouterPortHasBfd(lrp._uuid, has_bfd). -relation RouterPortNetworksIPv4Addr(port: Ref, addr: ipv4_netaddr) +relation RouterPortNetworksIPv4Addr(port: Intern, addr: ipv4_netaddr) RouterPortNetworksIPv4Addr(port, addr) :- port in &RouterPort(.networks = networks), var addr = FlatMap(networks.ipv4_addrs). -relation RouterPortNetworksIPv6Addr(port: Ref, addr: ipv6_netaddr) +relation RouterPortNetworksIPv6Addr(port: Intern, addr: ipv6_netaddr) RouterPortNetworksIPv6Addr(port, addr) :- port in &RouterPort(.networks = networks), @@ -733,7 +738,7 @@ RouterStaticRoute_(.router = router, typedef route_dst = RouteDst { nexthop: v46_ip, src_ip: v46_ip, - port: Ref, + port: Intern, ecmp_symmetric_reply: bool } diff --git a/northd/lswitch.dl b/northd/lswitch.dl index c089fadac863..aff265bbf82c 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -27,7 +27,7 @@ function is_enabled(lsp: Ref): bool { lsp.deref().is_en function is_enabled(sp: SwitchPort): bool { sp.lsp.is_enabled() } function is_enabled(sp: Intern): bool { sp.lsp.is_enabled() } -relation SwitchRouterPeerRef(lsp: uuid, rport: Option>) +relation SwitchRouterPeerRef(lsp: uuid, rport: Option>) SwitchRouterPeerRef(lsp, Some{rport}) :- SwitchRouterPeer(lsp, _, lrp), @@ -555,7 +555,7 @@ typedef SwitchPort = SwitchPort { lsp: nb::Logical_Switch_Port, json_name: string, sw: Intern, - peer: Option>, + peer: Option>, static_addresses: Vec, dynamic_address: Option, static_dynamic_mac: Option, diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index c4d46b2a8406..9e53821719c9 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -192,7 +192,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, Some{"router"} -> match ((l3dgw_port, opt_chassis, peer)) { (None, None, _) -> set_empty(), (_, _, None) -> set_empty(), - (_, _, Some{rport}) -> get_nat_addresses(deref(rport)) + (_, _, Some{rport}) -> get_nat_addresses(rport) }, Some{nat_addresses} -> { /* Only accept manual specification of ethernet address @@ -233,7 +233,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, (rport.router.options.contains_key("chassis") and not sw.localnet_ports.is_empty())) { false -> set_empty(), - true -> set_singleton(get_garp_nat_addresses(deref(rport))) + true -> set_singleton(get_garp_nat_addresses(rport)) }, None -> set_empty() }, @@ -316,7 +316,7 @@ function get_router_load_balancer_ips(router: Intern) : * external IP addresses of all NAT rules defined on that router, and all * of the IP addresses used in load balancer VIPs defined on that router. */ -function get_nat_addresses(rport: RouterPort): Set = +function get_nat_addresses(rport: Intern): Set = { var addresses = set_empty(); var has_redirect = rport.router.l3dgw_port.is_some(); @@ -391,7 +391,7 @@ function get_nat_addresses(rport: RouterPort): Set = } } -function get_garp_nat_addresses(rport: RouterPort): string = { +function get_garp_nat_addresses(rport: Intern): string = { var garp_info = ["${rport.networks.ea}"]; for (ipv4_addr in rport.networks.ipv4_addrs) { garp_info.push("${ipv4_addr.addr}") @@ -4037,7 +4037,7 @@ for (SwitchPortStaticAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json /* Returns 'true' if the IP 'addr' is on the same subnet with one of the * IPs configured on the router port. */ -function lrouter_port_ip_reachable(rp: Ref, addr: v46_ip): bool { +function lrouter_port_ip_reachable(rp: Intern, addr: v46_ip): bool { match (addr) { IPv4{ipv4} -> { for (na in rp.networks.ipv4_addrs) { @@ -4086,7 +4086,7 @@ UniqueFlow[Flow{.logical_datapath = sw._uuid, * router port. * Priority: 80. */ -function get_arp_forward_ips(rp: Ref): (Set, Set) = { +function get_arp_forward_ips(rp: Intern): (Set, Set) = { var all_ips_v4 = set_empty(); var all_ips_v6 = set_empty(); @@ -6322,7 +6322,7 @@ for (&Router(._uuid = lr_uuid)) * the following rule. */ relation Route(key: route_key, // matching criteria - port: Ref, // output port + port: Intern, // output port src_ip: v46_ip, // source IP address for output gateway: Option) // next hop (unless being delivered) From patchwork Sat Mar 27 00:31:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459080 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fw10BG6z9sCD for ; Sat, 27 Mar 2021 11:33:36 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id AD6C384E07; Sat, 27 Mar 2021 00:33:33 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id IJgWjco8ufk4; Sat, 27 Mar 2021 00:33:32 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTP id 1C58984E5D; Sat, 27 Mar 2021 00:33:05 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 12574C001C; Sat, 27 Mar 2021 00:33:04 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1B69AC0013 for ; Sat, 27 Mar 2021 00:33:03 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 088B960DE1 for ; Sat, 27 Mar 2021 00:32:32 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id giBXWLXAGcrJ for ; Sat, 27 Mar 2021 00:32:27 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp3.osuosl.org (Postfix) with ESMTPS id 749CB60DC1 for ; Sat, 27 Mar 2021 00:32:20 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id A164BFF802; Sat, 27 Mar 2021 00:32:17 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:40 -0700 Message-Id: <20210327003147.2955790-15-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 14/21] ovn-northd-ddlog: Remove unused function. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/lswitch.dl | 1 - 1 file changed, 1 deletion(-) diff --git a/northd/lswitch.dl b/northd/lswitch.dl index aff265bbf82c..973faec5073f 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -23,7 +23,6 @@ import ipam import vec function is_enabled(lsp: nb::Logical_Switch_Port): bool { is_enabled(lsp.enabled) } -function is_enabled(lsp: Ref): bool { lsp.deref().is_enabled() } function is_enabled(sp: SwitchPort): bool { sp.lsp.is_enabled() } function is_enabled(sp: Intern): bool { sp.lsp.is_enabled() } From patchwork Sat Mar 27 00:31:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459082 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fw80hQDz9sCD for ; Sat, 27 Mar 2021 11:33:44 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 27F5184EB6; Sat, 27 Mar 2021 00:33:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Uznbm9gjHqeF; Sat, 27 Mar 2021 00:33:39 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp1.osuosl.org (Postfix) with ESMTP id D348A84E71; Sat, 27 Mar 2021 00:33:12 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 95256C000B; Sat, 27 Mar 2021 00:33:12 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 21858C000D for ; Sat, 27 Mar 2021 00:33:11 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 3190F60DA7 for ; Sat, 27 Mar 2021 00:32:34 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id sEt4e8ciMD8Y for ; Sat, 27 Mar 2021 00:32:29 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp3.osuosl.org (Postfix) with ESMTPS id 1DD7660DA3 for ; Sat, 27 Mar 2021 00:32:21 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 54ADFFF803; Sat, 27 Mar 2021 00:32:19 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:41 -0700 Message-Id: <20210327003147.2955790-16-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 15/21] ovn-northd-ddlog: Eliminate remaining Ref's. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Change all remaining occurrences of `Ref` to `Intern` throughout the DDlog code base. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/helpers.dl | 36 +++++++++++++------------- northd/lrouter.dl | 22 ++++++++-------- northd/lswitch.dl | 61 ++++++++++++++++++++++++-------------------- northd/multicast.dl | 49 ++++++++++++++++++++--------------- northd/ovn_northd.dl | 8 +++--- 5 files changed, 95 insertions(+), 81 deletions(-) diff --git a/northd/helpers.dl b/northd/helpers.dl index 32a5526d59d5..49281fcafc9a 100644 --- a/northd/helpers.dl +++ b/northd/helpers.dl @@ -21,40 +21,40 @@ import ovn output relation Warning[string] /* ACLRef: reference to nb::ACL */ -relation &ACLRef[nb::ACL] -&ACLRef[acl] :- nb::ACL[acl]. +relation ACLRef[Intern] +ACLRef[acl.intern()] :- nb::ACL[acl]. /* DHCP_Options: reference to nb::DHCP_Options */ -relation &DHCP_OptionsRef[nb::DHCP_Options] -&DHCP_OptionsRef[options] :- nb::DHCP_Options[options]. +relation DHCP_OptionsRef[Intern] +DHCP_OptionsRef[options.intern()] :- nb::DHCP_Options[options]. /* QoS: reference to nb::QoS */ -relation &QoSRef[nb::QoS] -&QoSRef[qos] :- nb::QoS[qos]. +relation QoSRef[Intern] +QoSRef[qos.intern()] :- nb::QoS[qos]. /* LoadBalancerRef: reference to nb::Load_Balancer */ -relation &LoadBalancerRef[nb::Load_Balancer] -&LoadBalancerRef[lb] :- nb::Load_Balancer[lb]. +relation LoadBalancerRef[Intern] +LoadBalancerRef[lb.intern()] :- nb::Load_Balancer[lb]. /* LoadBalancerHealthCheckRef: reference to nb::Load_Balancer_Health_Check */ -relation &LoadBalancerHealthCheckRef[nb::Load_Balancer_Health_Check] -&LoadBalancerHealthCheckRef[lbhc] :- nb::Load_Balancer_Health_Check[lbhc]. +relation LoadBalancerHealthCheckRef[Intern] +LoadBalancerHealthCheckRef[lbhc.intern()] :- nb::Load_Balancer_Health_Check[lbhc]. /* MeterRef: reference to nb::Meter*/ -relation &MeterRef[nb::Meter] -&MeterRef[meter] :- nb::Meter[meter]. +relation MeterRef[Intern] +MeterRef[meter.intern()] :- nb::Meter[meter]. /* NATRef: reference to nb::NAT*/ -relation &NATRef[nb::NAT] -&NATRef[nat] :- nb::NAT[nat]. +relation NATRef[Intern] +NATRef[nat.intern()] :- nb::NAT[nat]. /* AddressSetRef: reference to nb::Address_Set */ -relation &AddressSetRef[nb::Address_Set] -&AddressSetRef[__as] :- nb::Address_Set[__as]. +relation AddressSetRef[Intern] +AddressSetRef[__as.intern()] :- nb::Address_Set[__as]. /* ServiceMonitor: reference to sb::Service_Monitor */ -relation &ServiceMonitorRef[sb::Service_Monitor] -&ServiceMonitorRef[sm] :- sb::Service_Monitor[sm]. +relation ServiceMonitorRef[Intern] +ServiceMonitorRef[sm.intern()] :- sb::Service_Monitor[sm]. /* Switch-to-router logical port connections */ relation SwitchRouterPeer(lsp: uuid, lsp_name: string, lrp: uuid) diff --git a/northd/lrouter.dl b/northd/lrouter.dl index e4e5cbf9f212..23d320be6cc7 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -263,11 +263,11 @@ LogicalRouterRedirectPort(lr, None) :- nb::Logical_Router(._uuid = lr), not DistributedGatewayPort(_, lr). -typedef ExceptionalExtIps = AllowedExtIps{ips: Ref} - | ExemptedExtIps{ips: Ref} +typedef ExceptionalExtIps = AllowedExtIps{ips: Intern} + | ExemptedExtIps{ips: Intern} typedef NAT = NAT{ - nat: Ref, + nat: Intern, external_ip: v46_ip, external_mac: Option, exceptional_ext_ips: Option @@ -275,7 +275,7 @@ typedef NAT = NAT{ relation LogicalRouterNAT0( lr: uuid, - nat: Ref, + nat: Intern, external_ip: v46_ip, external_mac: Option) LogicalRouterNAT0(lr, nat, external_ip, external_mac) :- @@ -399,14 +399,14 @@ LogicalRouterSnatIPs(lr._uuid, map_empty()) :- lr in nb::Logical_Router(), not LogicalRouterSnatIP(.lr = lr._uuid). -relation LogicalRouterLB(lr: uuid, nat: Ref) +relation LogicalRouterLB(lr: uuid, nat: Intern) LogicalRouterLB(lr, lb) :- nb::Logical_Router(._uuid = lr, .load_balancer = lbs), var lb_uuid = FlatMap(lbs), lb in &LoadBalancerRef[nb::Load_Balancer{._uuid = lb_uuid}]. -relation LogicalRouterLBs(lr: uuid, nat: Vec>) +relation LogicalRouterLBs(lr: uuid, nat: Vec>) LogicalRouterLBs(lr, lbs) :- LogicalRouterLB(lr, lb), @@ -448,8 +448,8 @@ typedef Router = Router { is_gateway: bool, nats: Vec, snat_ips: Map>, - lbs: Vec>, - mcast_cfg: Ref, + lbs: Vec>, + mcast_cfg: Intern, learn_from_arp_request: bool, force_lb_snat: bool, } @@ -491,7 +491,7 @@ Router[Router{ var force_lb_snat = lb_force_snat_router_ip(lr.options). /* RouterLB: many-to-many relation between logical routers and nb::LB */ -relation RouterLB(router: Intern, lb: Ref) +relation RouterLB(router: Intern, lb: Intern) RouterLB(router, lb) :- router in &Router(.lbs = lbs), @@ -500,7 +500,7 @@ RouterLB(router, lb) :- /* Load balancer VIPs associated with routers */ relation RouterLBVIP( router: Intern, - lb: Ref, + lb: Intern, vip: string, backends: string) @@ -582,7 +582,7 @@ typedef RouterPort = RouterPort { router: Intern, is_redirect: bool, peer: RouterPeer, - mcast_cfg: Ref, + mcast_cfg: Intern, sb_options: Map, has_bfd: bool } diff --git a/northd/lswitch.dl b/northd/lswitch.dl index 973faec5073f..df74a3731c1d 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -201,7 +201,7 @@ typedef Switch = Switch { localnet_ports: Vec<(uuid, string)>, // UUID and name of each localnet port. subnet: Option<(in_addr/*subnet*/, in_addr/*mask*/, bit<32>/*start_ipv4*/, bit<32>/*total_ipv4s*/)>, ipv6_prefix: Option, - mcast_cfg: Ref, + mcast_cfg: Intern, is_vlan_transparent: bool, /* Does this switch have at least one port with type != "router"? */ @@ -276,14 +276,14 @@ Switch[Switch{ var is_vlan_transparent = ls.other_config.get_bool_def("vlan-passthru", false). /* SwitchLB: many-to-many relation between logical switches and nb::LB */ -relation SwitchLB(sw_uuid: uuid, lb: Ref) +relation SwitchLB(sw_uuid: uuid, lb: Intern) SwitchLB(sw_uuid, lb) :- nb::Logical_Switch(._uuid = sw_uuid, .load_balancer = lb_ids), var lb_id = FlatMap(lb_ids), lb in &LoadBalancerRef[nb::Load_Balancer{._uuid = lb_id}]. /* Load balancer VIPs associated with switch */ -relation SwitchLBVIP(sw_uuid: uuid, lb: Ref, vip: string, backends: string) +relation SwitchLBVIP(sw_uuid: uuid, lb: Intern, vip: string, backends: string) SwitchLBVIP(sw_uuid, lb, vip, backends) :- SwitchLB(sw_uuid, lb@(&nb::Load_Balancer{.vips = vips})), var kv = FlatMap(vips), @@ -304,10 +304,10 @@ LogicalSwitchHasLBVIP(sw_uuid, false) :- * - LBVIP parses the IP address and port (and drops VIPs where those are invalid). */ relation LBVIP0( - lb: Ref, + lb: Intern, vip_key: string, backend_ips: string, - health_check: Ref) + health_check: Intern) LBVIP0(lb, vip_key, backend_ips, health_check) :- LoadBalancerRef[lb], var vip = FlatMap(lb.vips), @@ -316,10 +316,10 @@ LBVIP0(lb, vip_key, backend_ips, health_check) :- lb.health_check.contains(health_check._uuid). relation LBVIP1( - lb: Ref, + lb: Intern, vip_key: string, backend_ips: string, - health_check: Option>) + health_check: Option>) LBVIP1(lb, vip_key, backend_ips, Some{health_check}) :- LBVIP0(lb, vip_key, backend_ips, health_check). LBVIP1(lb, vip_key, backend_ips, None) :- @@ -328,15 +328,19 @@ LBVIP1(lb, vip_key, backend_ips, None) :- (var vip_key, var backend_ips) = vip, not LBVIP0(lb, vip_key, backend_ips, _). -relation &LBVIP( - lb: Ref, +typedef LBVIP = LBVIP { + lb: Intern, vip_key: string, backend_ips: string, - health_check: Option>, + health_check: Option>, vip_addr: v46_ip, vip_port: bit<16>, - backends: Vec) -&LBVIP(lb, vip_key, backend_ips, health_check, vip_addr, vip_port, backends) :- + backends: Vec +} + +relation LBVIP[Intern] + +LBVIP[LBVIP{lb, vip_key, backend_ips, health_check, vip_addr, vip_port, backends}.intern()] :- LBVIP1(lb, vip_key, backend_ips, health_check), Some{(var vip_addr, var vip_port)} = ip_address_and_port_from_lb_key(vip_key), var backends = backend_ips.split(",").filter_map( @@ -398,17 +402,20 @@ function default_protocol(protocol: Option): string = { } } -relation &LBVIPWithStatus( - lb: Ref, +typedef LBVIPWithStatus = LBVIPWithStatus { + lb: Intern, vip_key: string, backend_ips: string, - health_check: Option>, + health_check: Option>, vip_addr: v46_ip, vip_port: bit<16>, - backends: Map) -&LBVIPWithStatus(lb, vip_key, backend_ips, health_check, vip_addr, vip_port, map_empty()) :- + backends: Map +} +relation LBVIPWithStatus[Intern] + +LBVIPWithStatus[LBVIPWithStatus{lb, vip_key, backend_ips, health_check, vip_addr, vip_port, map_empty()}.intern()] :- &LBVIP(lb, vip_key, backend_ips, health_check, vip_addr, vip_port, vec_empty()). -&LBVIPWithStatus(lb, vip_key, backend_ips, health_check, vip_addr, vip_port, backends_with_status) :- +LBVIPWithStatus[LBVIPWithStatus{lb, vip_key, backend_ips, health_check, vip_addr, vip_port, backends_with_status}.intern()] :- &LBVIP(lb, vip_key, backend_ips, health_check, vip_addr, vip_port, backends), var backend = FlatMap(backends), LBVIPBackendStatus(lbvip, backend, up), @@ -420,7 +427,7 @@ relation &LBVIPWithStatus( * Only some backends have health checking enabled. The ones that don't * are always considered to be up. */ relation LBVIPBackendStatus0( - lbvip: Ref, + lbvip: Intern, backend: lb_vip_backend, up: bool) LBVIPBackendStatus0(lbvip, backend, is_online(sm.status)) :- @@ -433,7 +440,7 @@ LBVIPBackendStatus0(lbvip, backend, is_online(sm.status)) :- default_protocol(lb.protocol) == default_protocol(sm.protocol). relation LBVIPBackendStatus( - lbvip: Ref, + lbvip: Intern, backend: lb_vip_backend, up: bool) LBVIPBackendStatus(lbvip, backend, up) :- LBVIPBackendStatus0(lbvip, backend, up). @@ -445,7 +452,7 @@ LBVIPBackendStatus(lbvip, backend, true) :- /* SwitchPortDHCPv4Options: many-to-one relation between logical switches and DHCPv4 options */ relation SwitchPortDHCPv4Options( port: Intern, - dhcpv4_options: Ref) + dhcpv4_options: Intern) SwitchPortDHCPv4Options(port, options) :- port in &SwitchPort(.lsp = lsp), @@ -456,7 +463,7 @@ SwitchPortDHCPv4Options(port, options) :- /* SwitchPortDHCPv6Options: many-to-one relation between logical switches and DHCPv4 options */ relation SwitchPortDHCPv6Options( port: Intern, - dhcpv6_options: Ref) + dhcpv6_options: Intern) SwitchPortDHCPv6Options(port, options) :- port in &SwitchPort(.lsp = lsp), @@ -465,7 +472,7 @@ SwitchPortDHCPv6Options(port, options) :- options in &DHCP_OptionsRef[nb::DHCP_Options{._uuid = dhcpv6_uuid}]. /* SwitchQoS: many-to-one relation between logical switches and nb::QoS */ -relation SwitchQoS(sw: Intern, qos: Ref) +relation SwitchQoS(sw: Intern, qos: Intern) SwitchQoS(sw, qos) :- sw in &Switch(), @@ -478,7 +485,7 @@ SwitchQoS(sw, qos) :- * that isn't a fair meter. (The latter case has two subcases: the * case where the meter that the ACL names corresponds to an nb::Meter * with that name, and the case where it doesn't.) */ -relation ACLHasFairMeter(acl: Ref, has_fair_meter: bool) +relation ACLHasFairMeter(acl: Intern, has_fair_meter: bool) ACLHasFairMeter(acl, true) :- ACLWithFairMeter(acl, _). ACLHasFairMeter(acl, false) :- @@ -486,14 +493,14 @@ ACLHasFairMeter(acl, false) :- not ACLWithFairMeter(acl, _). /* All the ACLs associated with a fair meter, with their fair meters. */ -relation ACLWithFairMeter(acl: Ref, meter: Ref) +relation ACLWithFairMeter(acl: Intern, meter: Intern) ACLWithFairMeter(acl, meter) :- acl in &ACLRef[nb::ACL{.meter = Some{meter_name}}], meter in &MeterRef[nb::Meter{.name = meter_name, .fair = Some{true}}]. /* SwitchACL: many-to-many relation between logical switches and ACLs */ relation &SwitchACL(sw: Intern, - acl: Ref, + acl: Intern, has_fair_meter: bool) &SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = has_fair_meter) :- @@ -568,7 +575,7 @@ typedef SwitchPort = SwitchPort { needs_dynamic_ipv6address: bool, needs_dynamic_tag: bool, up: bool, - mcast_cfg: Ref, + mcast_cfg: Intern, hac_group_uuid: Option } diff --git a/northd/multicast.dl b/northd/multicast.dl index 5a14a90da1cd..9e3c13a3fde0 100644 --- a/northd/multicast.dl +++ b/northd/multicast.dl @@ -31,7 +31,7 @@ function mCAST_QUERY_INTERVAL_S_RANGE(): (integer, integer) = (1, 3600) function mCAST_DEFAULT_QUERY_MAX_RESPONSE_S(): integer = 1 /* IP Multicast per switch configuration. */ -relation &McastSwitchCfg( +typedef McastSwitchCfg = McastSwitchCfg { datapath : uuid, enabled : bool, querier : bool, @@ -43,24 +43,27 @@ relation &McastSwitchCfg( idle_timeout : integer, query_interval: integer, query_max_resp: integer -) +} + +relation McastSwitchCfg[Intern] /* FIXME: Right now table_size is enforced only in ovn-controller but in * the ovn-northd C version we enforce it on the aggregate groups too. */ -&McastSwitchCfg( - .datapath = ls_uuid, - .enabled = other_config.get_bool_def("mcast_snoop", false), - .querier = other_config.get_bool_def("mcast_querier", true), - .flood_unreg = other_config.get_bool_def("mcast_flood_unregistered", false), - .eth_src = other_config.get("mcast_eth_src").unwrap_or(""), - .ip4_src = other_config.get("mcast_ip4_src").unwrap_or(""), - .ip6_src = other_config.get("mcast_ip6_src").unwrap_or(""), - .table_size = other_config.get_int_def("mcast_table_size", mCAST_DEFAULT_MAX_ENTRIES()), - .idle_timeout = idle_timeout, - .query_interval = query_interval, - .query_max_resp = query_max_resp) :- +McastSwitchCfg[McastSwitchCfg { + .datapath = ls_uuid, + .enabled = other_config.get_bool_def("mcast_snoop", false), + .querier = other_config.get_bool_def("mcast_querier", true), + .flood_unreg = other_config.get_bool_def("mcast_flood_unregistered", false), + .eth_src = other_config.get("mcast_eth_src").unwrap_or(""), + .ip4_src = other_config.get("mcast_ip4_src").unwrap_or(""), + .ip6_src = other_config.get("mcast_ip6_src").unwrap_or(""), + .table_size = other_config.get_int_def("mcast_table_size", mCAST_DEFAULT_MAX_ENTRIES()), + .idle_timeout = idle_timeout, + .query_interval = query_interval, + .query_max_resp = query_max_resp + }.intern()] :- nb::Logical_Switch(._uuid = ls_uuid, .other_config = other_config), var idle_timeout = other_config.get_int_def("mcast_idle_timeout", mCAST_DEFAULT_IDLE_TIMEOUT_S()) @@ -71,29 +74,33 @@ relation &McastSwitchCfg( mCAST_DEFAULT_QUERY_MAX_RESPONSE_S()). /* IP Multicast per router configuration. */ -relation &McastRouterCfg( +typedef McastRouterCfg = McastRouterCfg { datapath: uuid, relay : bool -) +} -&McastRouterCfg(lr_uuid, mcast_relay) :- +relation McastRouterCfg[Intern] + +McastRouterCfg[McastRouterCfg{lr_uuid, mcast_relay}.intern()] :- nb::Logical_Router(._uuid = lr_uuid, .options = options), var mcast_relay = options.get_bool_def("mcast_relay", false). /* IP Multicast port configuration. */ -relation &McastPortCfg( +typedef McastPortCfg = McastPortCfg { port : uuid, router_port : bool, flood : bool, flood_reports : bool -) +} + +relation McastPortCfg[Intern] -&McastPortCfg(lsp_uuid, false, flood, flood_reports) :- +McastPortCfg[McastPortCfg{lsp_uuid, false, flood, flood_reports}.intern()] :- nb::Logical_Switch_Port(._uuid = lsp_uuid, .options = options), var flood = options.get_bool_def("mcast_flood", false), var flood_reports = options.get_bool_def("mcast_flood_reports", false). -&McastPortCfg(lrp_uuid, true, flood, flood) :- +McastPortCfg[McastPortCfg{lrp_uuid, true, flood, flood}.intern()] :- nb::Logical_Router_Port(._uuid = lrp_uuid, .options = options), var flood = options.get_bool_def("mcast_flood", false). diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 9e53821719c9..f2ada73bf8ed 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -295,7 +295,7 @@ function get_router_load_balancer_ips(router: Intern) : var all_ips_v4 = set_empty(); var all_ips_v6 = set_empty(); for (lb in router.lbs) { - for (kv in deref(lb).vips) { + for (kv in lb.vips) { (var vip, _) = kv; /* node->key contains IP:port or just IP. */ match (ip_address_and_port_from_lb_key(vip)) { @@ -2000,7 +2000,7 @@ HasEventElbMeter(false) :- not nb::Meter(.name = "event-elb"). /* Empty LoadBalancer Controller event */ -function build_empty_lb_event_flow(key: string, lb: Ref, +function build_empty_lb_event_flow(key: string, lb: Intern, meter: bool): Option<(string, string)> { (var ip, var port) = match (ip_address_and_port_from_lb_key(key)) { Some{(ip, port)} -> (ip, port), @@ -2045,7 +2045,7 @@ function build_empty_lb_event_flow(key: string, lb: Ref, * The deprecated way is to set nb::NB_Global options:controller_event=true, * which enables events for every load balancer. */ -relation LoadBalancerEmptyEvents(lb: Ref) +relation LoadBalancerEmptyEvents(lb: Intern) LoadBalancerEmptyEvents(lb) :- nb::NB_Global(.options = global_options), var global_events = global_options.get_bool_def("controller_event", false), @@ -2920,7 +2920,7 @@ function ct_lb(backends: string, "ct_lb(" ++ args.join("; ") ++ ");" } -function build_lb_vip_actions(lbvip: Ref, +function build_lb_vip_actions(lbvip: Intern, stage: Stage, actions0: string): string { var up_backends = set_empty(); From patchwork Sat Mar 27 00:31:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459083 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fwJ1dgCz9sCD for ; Sat, 27 Mar 2021 11:33:52 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 59A9060EE1; Sat, 27 Mar 2021 00:33:50 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZNUcJ8CibLko; Sat, 27 Mar 2021 00:33:45 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTP id 253B860DC2; Sat, 27 Mar 2021 00:33:16 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 91720C000B; Sat, 27 Mar 2021 00:33:15 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1BB53C0013 for ; Sat, 27 Mar 2021 00:33:14 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id F265C40673 for ; Sat, 27 Mar 2021 00:32:35 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zuEmXNOtbqiW for ; Sat, 27 Mar 2021 00:32:32 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp2.osuosl.org (Postfix) with ESMTPS id ADC1A4069D for ; Sat, 27 Mar 2021 00:32:23 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id F3253FF804; Sat, 27 Mar 2021 00:32:20 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:42 -0700 Message-Id: <20210327003147.2955790-17-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 16/21] ovn-northd-ddlog: Eliminate redundant dereferences. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk We eliminate an anti-pattern in the use of smart pointers that occurred throughout the DDlog code. Consider relation `A` that contains field `x` wrapped in a DDlog smart pointer (`Intern<>` or `Ref<>`): ``` relation A(x: Intern, ...) ``` Here `T` might be a complex type with dynamically allocated fields like vectors and maps, etc. Here is how _not_ to use this relation in a rule: ``` Rel(...) :- A(.x = &v), B(v.field1), C(v.field2). ``` The `&v` syntax here extracts the inner value that the smart pointer points to and binds it to variable `v`. Thus, the type of `v` is `T` and we thread the value of `T` through the entire rule, which requires creating two more copies of it (types not wrapped in smart pointers are copied by value). This is a waste of memory and CPU and is completely unnecessary, as we can instead bind `v` to the value of the smart pointer, so it can be copied efficiently: ``` Rel(...) :- A(.x = v), // type of `v` is `Intern`. B(v.field1), C(v.field2). ``` The inefficient usage if a leftover from the days when DDlog had some awkward restrictions on the use of smart pointers. Note that `&` is still useful and does not incur any overhead when used to deconstruct an object wrapped in a smart pointer and refer to its fields, e.g.: ``` Rel(...) :- // Bind `f1` and `f2` to `x.field1` and `x.field2`; // filter out records where `field3` is `false`. A(.x = &T{.field1 = f1, .field2 = f2, .field3 = true}), B(f1), C(f2). ``` On top of this, the `@` operator can be used to simultaneously bind the entire value stored in `x` and its individual fields. ``` Rel(...) :- // Bind `v` to the value of field `x` (`v: Intern`); // bind `f2` to `x.field2`; filter on the value of `field3`. A(.x = v @ &T{.field2 = f2, .field3 = true}), B(v.field1), C(f2). ``` The `&` in this rule is used to deconstruct the value inside the smart pointer; however since the binding operator `@` preceeds `&`, we bind `v` to the value of the smart pointer and not the type that it wraps. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/ipam.dl | 14 +++--- northd/multicast.dl | 4 +- northd/ovn_northd.dl | 104 +++++++++++++++++++++---------------------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/northd/ipam.dl b/northd/ipam.dl index 40d542ec0687..da71b2872952 100644 --- a/northd/ipam.dl +++ b/northd/ipam.dl @@ -161,7 +161,7 @@ SwitchIPv4ReservedAddress(.lswitch = ls_uuid, &SwitchPort( .sw = &Switch{._uuid = ls_uuid, .subnet = Some{(_, _, start_ipv4, total_ipv4s)}}, - .peer = Some{&rport}), + .peer = Some{rport}), var addrs = { var addrs = set_empty(); for (addr in rport.networks.ipv4_addrs) { @@ -177,7 +177,7 @@ SwitchIPv4ReservedAddress(.lswitch = ls_uuid, /* Add reserved address group (5) */ SwitchIPv4ReservedAddress(.lswitch = sw._uuid, .addr = ip_addr.a) :- - &SwitchPort(.sw = &sw, .lsp = lsp, .static_dynamic_ipv4 = Some{ip_addr}). + &SwitchPort(.sw = sw, .lsp = lsp, .static_dynamic_ipv4 = Some{ip_addr}). /* Aggregate all reserved addresses for each switch. */ relation SwitchIPv4ReservedAddresses(lswitch: uuid, addrs: Set>) @@ -197,7 +197,7 @@ relation SwitchPortAllocatedIPv4DynAddress(lsport: uuid, dyn_addr: Option) SwitchPortNewIPv4DynAddress(lsp._uuid, ip_addr) :- - &SwitchPort(.sw = &sw, + &SwitchPort(.sw = sw, .needs_dynamic_ipv4address = false, .static_dynamic_ipv4 = static_dynamic_ipv4, .lsp = lsp), @@ -333,7 +333,7 @@ ReservedMACAddress(.addr = mac_addr.ha) :- /* Add reserved address group (3). */ ReservedMACAddress(.addr = rport.networks.ea.ha) :- - &SwitchPort(.peer = Some{&rport}). + &SwitchPort(.peer = Some{rport}). /* Aggregate all reserved MAC addresses. */ relation ReservedMACAddresses(addrs: Set>) @@ -430,7 +430,7 @@ relation SwitchPortNewMACDynAddress(lsport: uuid, dyn_addr: Option) SwitchPortNewMACDynAddress(lsp._uuid, mac_addr) :- &SwitchPort(.needs_dynamic_macaddress = false, .lsp = lsp, - .sw = &sw, + .sw = sw, .static_dynamic_mac = static_dynamic_mac), var mac_addr = match (static_dynamic_mac) { None -> None, @@ -467,7 +467,7 @@ SwitchPortNewDynamicAddress(port, None) :- SwitchPortNewDynamicAddress(port, lport_address) :- port in &SwitchPort(.lsp = lsp, - .sw = &sw, + .sw = sw, .needs_dynamic_ipv6address = needs_dynamic_ipv6address, .static_dynamic_ipv6 = static_dynamic_ipv6), SwitchPortNewMACDynAddress(lsp._uuid, Some{mac_addr}), diff --git a/northd/multicast.dl b/northd/multicast.dl index 9e3c13a3fde0..25fcd2938f6b 100644 --- a/northd/multicast.dl +++ b/northd/multicast.dl @@ -113,7 +113,7 @@ SwitchMcastFloodRelayPorts(switch, relay_ports) :- &SwitchPort( .lsp = lsp, .sw = switch, - .peer = Some{&RouterPort{.router = &Router{.mcast_cfg = &mcast_cfg}}} + .peer = Some{&RouterPort{.router = &Router{.mcast_cfg = mcast_cfg}}} ), mcast_cfg.relay, var relay_ports = lsp._uuid.group_by(switch).to_set(). @@ -236,7 +236,7 @@ IgmpRouterGroupPort(address, rtr_port.router, rtr_port.lrp._uuid) :- }, var flood_port = FlatMap(sw_flood_ports), &SwitchPort(.lsp = nb::Logical_Switch_Port{._uuid = flood_port}, - .peer = Some{&rtr_port}). + .peer = Some{rtr_port}). /* Aggregated IGMP group for routers: merges all IgmpRouterGroupPort for * a given address-router tuple from all connected switches. diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index f2ada73bf8ed..5476a6f2e85f 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -132,7 +132,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, .mac = lsp.addresses, .nat_addresses = set_empty(), .external_ids = eids) :- - sp in &SwitchPort(.lsp = lsp, .sw = &sw), + sp in &SwitchPort(.lsp = lsp, .sw = sw), SwitchPortNewDynamicTag(lsp._uuid, opt_tag), var tag = match (opt_tag) { None -> lsp.tag, @@ -162,7 +162,7 @@ OutProxy_Port_Binding(._uuid = lsp._uuid, .mac = lsp.addresses, .nat_addresses = nat_addresses, .external_ids = eids) :- - &SwitchPort(.lsp = lsp, .sw = &sw, .peer = peer), + &SwitchPort(.lsp = lsp, .sw = sw, .peer = peer), var eids = { var eids = lsp.external_ids; match (lsp.external_ids.get("neutron:port_name")) { @@ -252,7 +252,7 @@ OutProxy_Port_Binding(._uuid = lrp._uuid, .mac = set_singleton("${lrp.mac} ${lrp.networks.join(\" \")}"), .nat_addresses = set_empty(), .external_ids = lrp.external_ids) :- - rp in &RouterPort(.lrp = lrp, .router = &router, .peer = peer), + rp in &RouterPort(.lrp = lrp, .router = router, .peer = peer), RouterPortRAOptionsComplete(lrp._uuid, options0), (var __type, var options1) = match (router.options.get("chassis")) { /* TODO: derived ports */ @@ -877,7 +877,7 @@ sb::Out_Multicast_Group (._uuid = hash128((sw._uuid,name)), .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- - SwitchMcastFloodRelayPorts(&sw, port_ids), + SwitchMcastFloodRelayPorts(sw, port_ids), not port_ids.is_empty(), (var name, var tunnel_key) = mC_MROUTER_FLOOD(). @@ -889,7 +889,7 @@ sb::Out_Multicast_Group (._uuid = hash128((sw._uuid,name)), .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- - SwitchMcastFloodPorts(&sw, port_ids), + SwitchMcastFloodPorts(sw, port_ids), not port_ids.is_empty(), (var name, var tunnel_key) = mC_STATIC(). @@ -901,7 +901,7 @@ sb::Out_Multicast_Group (._uuid = hash128((sw._uuid,name)), .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- - SwitchMcastFloodReportPorts(&sw, port_ids), + SwitchMcastFloodReportPorts(sw, port_ids), not port_ids.is_empty(), (var name, var tunnel_key) = mC_MROUTER_STATIC(). @@ -913,7 +913,7 @@ sb::Out_Multicast_Group (._uuid = hash128((rtr._uuid,name)), .name = name, .tunnel_key = tunnel_key, .ports = port_ids) :- - RouterMcastFloodPorts(&rtr, port_ids), + RouterMcastFloodPorts(rtr, port_ids), not port_ids.is_empty(), (var name, var tunnel_key) = mC_STATIC(). @@ -923,7 +923,7 @@ sb::Out_Multicast_Group (._uuid = hash128((rtr._uuid,name)), OutProxy_Multicast_Group (.datapath = switch._uuid, .name = address, .ports = port_ids) :- - IgmpSwitchMulticastGroup(address, &switch, port_ids). + IgmpSwitchMulticastGroup(address, switch, port_ids). /* Create a multicast group for each IGMP group learned by a Router. * 'tunnel_key' == 0 triggers an ID allocation later. @@ -931,7 +931,7 @@ OutProxy_Multicast_Group (.datapath = switch._uuid, OutProxy_Multicast_Group (.datapath = router._uuid, .name = address, .ports = port_ids) :- - IgmpRouterMulticastGroup(address, &router, port_ids). + IgmpRouterMulticastGroup(address, router, port_ids). /* Allocate a 'tunnel_key' for dynamic multicast groups. */ sb::Out_Multicast_Group(._uuid = hash128((mcgroup.datapath,mcgroup.name)), @@ -2150,7 +2150,7 @@ function acl_log_meter_name(meter_name: string, acl_uuid: uuid): string = meter_name ++ "__" ++ uuid2str(acl_uuid) } -function build_acl_log(acl: nb::ACL, fair_meter: bool): string = +function build_acl_log(acl: Intern, fair_meter: bool): string = { if (not acl.log) { "" @@ -2207,7 +2207,7 @@ relation Reject( lsuuid: uuid, pipeline: Pipeline, stage: Stage, - acl: nb::ACL, + acl: Intern, fair_meter: bool, extra_match: string, extra_actions: string) @@ -2502,7 +2502,7 @@ for (sw in &Switch(._uuid = ls_uuid)) { } /* Ingress or Egress ACL Table (Various priorities). */ -for (&SwitchACL(.sw = sw, .acl = &acl, .has_fair_meter = fair_meter)) { +for (&SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = fair_meter)) { /* consider_acl */ var has_stateful = sw.has_stateful_acl or sw.has_lb_vip in var ingress = acl.direction == "from-lport" in @@ -2619,7 +2619,7 @@ for (&SwitchACL(.sw = sw, .acl = &acl, .has_fair_meter = fair_meter)) { /* Add 34000 priority flow to allow DHCP reply from ovn-controller to all * logical ports of the datapath if the CMS has configured DHCPv4 options. * */ -for (SwitchPortDHCPv4Options(.port = &SwitchPort{.lsp = lsp, .sw = &sw}, +for (SwitchPortDHCPv4Options(.port = &SwitchPort{.lsp = lsp, .sw = sw}, .dhcpv4_options = dhcpv4_options@&nb::DHCP_Options{.options = options}) if lsp.__type != "external") { (Some{var server_id}, Some{var server_mac}, Some{var lease_time}) = @@ -2636,7 +2636,7 @@ for (SwitchPortDHCPv4Options(.port = &SwitchPort{.lsp = lsp, .sw = &sw}, .external_ids = stage_hint(dhcpv4_options._uuid)) } -for (SwitchPortDHCPv6Options(.port = &SwitchPort{.lsp = lsp, .sw = &sw}, +for (SwitchPortDHCPv6Options(.port = &SwitchPort{.lsp = lsp, .sw = sw}, .dhcpv6_options = dhcpv6_options@&nb::DHCP_Options{.options=options} ) if lsp.__type != "external") { Some{var server_mac} = options.get("server_id") in @@ -2691,7 +2691,7 @@ for (&Switch(._uuid = ls_uuid)) { .external_ids = map_empty()) } -for (SwitchQoS(.sw = &sw, .qos = &qos)) { +for (SwitchQoS(.sw = sw, .qos = qos)) { var ingress = if (qos.direction == "from-lport") true else false in var pipeline = if ingress "ingress" else "egress" in { var stage = if (ingress) { s_SWITCH_IN_QOS_MARK() } else { s_SWITCH_OUT_QOS_MARK() } in @@ -3045,7 +3045,7 @@ for (&Switch(._uuid = ls_uuid, .has_lb_vip = true)) { /* Logical switch ingress table PORT_SEC_L2: ingress port security - L2 (priority 50) ingress table PORT_SEC_IP: ingress port security - IP (priority 90 and 80) ingress table PORT_SEC_ND: ingress port security - ND (priority 90 and 80) */ -for (&SwitchPort(.lsp = lsp, .sw = &sw, .json_name = json_name, .ps_eth_addresses = ps_eth_addresses) +for (&SwitchPort(.lsp = lsp, .sw = sw, .json_name = json_name, .ps_eth_addresses = ps_eth_addresses) if lsp.is_enabled() and lsp.__type != "external") { for (pbinding in sb::Out_Port_Binding(.logical_port = lsp.name)) { var __match = if (ps_eth_addresses.is_empty()) { @@ -3081,7 +3081,7 @@ for (&SwitchPort(.lsp = lsp, .sw = &sw, .json_name = json_name, .ps_eth_addresse * - If the port security has IPv4 addresses or IPv6 addresses or both * - Priority 80 flow to drop all IPv4 and IPv6 traffic */ -for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) +for (SwitchPortPSAddresses(.port = port@&SwitchPort{.sw = sw}, .ps_addrs = ps) if port.is_enabled() and (ps.ipv4_addrs.len() > 0 or ps.ipv6_addrs.len() > 0) and port.lsp.__type != "external") @@ -3180,7 +3180,7 @@ for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) * * - Priority 80 flow to drop ARP and IPv6 ND packets. */ -for (SwitchPortPSAddresses(.port = &port@SwitchPort{.sw = &sw}, .ps_addrs = ps) +for (SwitchPortPSAddresses(.port = port@&SwitchPort{.sw = sw}, .ps_addrs = ps) if port.is_enabled() and port.lsp.__type != "external") { var no_ip = ps.ipv4_addrs.is_empty() and ps.ipv6_addrs.is_empty() in @@ -3247,7 +3247,7 @@ for (&Switch(._uuid = ls_uuid)) { /* Ingress table ARP_ND_RSP: ARP/ND responder, skip requests coming from * localnet and vtep ports. (priority 100); see ovn-northd.8.xml for the * rationale. */ -for (&SwitchPort(.lsp = lsp, .sw = &sw, .json_name = json_name) +for (&SwitchPort(.lsp = lsp, .sw = sw, .json_name = json_name) if lsp.is_enabled() and (lsp.__type == "localnet" or lsp.__type == "vtep")) { @@ -3295,7 +3295,7 @@ function lsp_is_up(lsp: nb::Logical_Switch_Port): bool = { * - port type is localport */ for (CheckLspIsUp[check_lsp_is_up]) { - for (SwitchPortIPv4Address(.port = &SwitchPort{.lsp = lsp, .sw = &sw, .json_name = json_name}, + for (SwitchPortIPv4Address(.port = &SwitchPort{.lsp = lsp, .sw = sw, .json_name = json_name}, .ea = ea, .addr = addr) if lsp.is_enabled() and ((lsp_is_up(lsp) or not check_lsp_is_up) @@ -3347,7 +3347,7 @@ for (CheckLspIsUp[check_lsp_is_up]) { /* For ND solicitations, we need to listen for both the * unicast IPv6 address and its all-nodes multicast address, * but always respond with the unicast IPv6 address. */ -for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = &sw}, +for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw}, .ea = ea, .addr = addr) if lsp.is_enabled() and (lsp_is_up(lsp) or lsp.__type == "router" or lsp.__type == "localport") and @@ -3785,7 +3785,7 @@ Flow(.logical_datapath = sw._uuid, .external_ids = map_empty()) :- sw in &Switch(). -for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = &mcast_cfg) +for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = mcast_cfg) if (mcast_cfg.enabled)) { for (SwitchMcastFloodRelayPorts(sw, relay_ports)) { for (SwitchMcastFloodReportPorts(sw, flood_report_ports)) { @@ -3890,7 +3890,7 @@ for (sw in &Switch(._uuid = ls_uuid, .mcast_cfg = &mcast_cfg) /* Ingress table L2_LKUP: Add IP multicast flows learnt from IGMP/MLD (priority * 90). */ -for (IgmpSwitchMulticastGroup(.address = address, .switch = &sw)) { +for (IgmpSwitchMulticastGroup(.address = address, .switch = sw)) { /* RFC 4541, section 2.1.2, item 2: Skip groups in the 224.0.0.X * range. * @@ -3903,8 +3903,8 @@ for (IgmpSwitchMulticastGroup(.address = address, .switch = &sw)) { IPv6{ipv6} -> ipv6.is_all_hosts() } in var ipX = ip.ipX() in - for (SwitchMcastFloodRelayPorts(&sw, relay_ports) if not skip_address) { - for (SwitchMcastFloodPorts(&sw, flood_ports)) { + for (SwitchMcastFloodRelayPorts(sw, relay_ports) if not skip_address) { + for (SwitchMcastFloodPorts(sw, flood_ports)) { var flood_relay = not relay_ports.is_empty() in var flood_static = not flood_ports.is_empty() in var mc_rtr_flood = json_string_escape(mC_MROUTER_FLOOD().0) in @@ -4012,7 +4012,7 @@ for (ls in nb::Logical_Switch) { /* Ingress table L2_LKUP: Destination lookup, unicast handling (priority 50). */ -for (SwitchPortStaticAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = &sw}, +for (SwitchPortStaticAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw}, .addrs = addrs) if lsp.__type != "external") { Flow(.logical_datapath = sw._uuid, @@ -4183,7 +4183,7 @@ AnnotatedFlow(.f = Flow{.logical_datapath = sw._uuid, not all_ips_v6.is_empty(), var mc_flood_l2 = json_string_escape(mC_FLOOD_L2().0). -for (SwitchPortNewDynamicAddress(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = &sw}, +for (SwitchPortNewDynamicAddress(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw}, .address = Some{addrs}) if lsp.__type != "external") { Flow(.logical_datapath = sw._uuid, @@ -4196,7 +4196,7 @@ for (SwitchPortNewDynamicAddress(.port = &SwitchPort{.lsp = lsp, .json_name = js for (&SwitchPort(.lsp = lsp, .json_name = json_name, - .sw = &sw, + .sw = sw, .peer = Some{&RouterPort{.lrp = lrp, .is_redirect = is_redirect, .router = &Router{._uuid = lr_uuid, @@ -4354,7 +4354,7 @@ Flow(.logical_datapath = sw._uuid, .__match = __match, .actions = queue_action ++ "output;", .external_ids = stage_hint(lsp._uuid)) :- - &SwitchPort(.sw = &sw, .lsp = lsp, .json_name = json_name, .ps_eth_addresses = ps_eth_addresses), + &SwitchPort(.sw = sw, .lsp = lsp, .json_name = json_name, .ps_eth_addresses = ps_eth_addresses), lsp.is_enabled(), lsp.__type != "external", var __match = if (ps_eth_addresses.is_empty()) { @@ -4369,7 +4369,7 @@ Flow(.logical_datapath = sw._uuid, _ -> "" }. -for (&SwitchPort(.lsp = lsp, .json_name = json_name, .sw = &sw) +for (&SwitchPort(.lsp = lsp, .json_name = json_name, .sw = sw) if not lsp.is_enabled() and lsp.__type != "external") { Flow(.logical_datapath = sw._uuid, .stage = s_SWITCH_OUT_PORT_SEC_L2(), @@ -4379,7 +4379,7 @@ for (&SwitchPort(.lsp = lsp, .json_name = json_name, .sw = &sw) .external_ids = stage_hint(lsp._uuid)) } -for (SwitchPortPSAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = &sw}, +for (SwitchPortPSAddresses(.port = &SwitchPort{.lsp = lsp, .json_name = json_name, .sw = sw}, .ps_addrs = ps) if (ps.ipv4_addrs.len() > 0 or ps.ipv6_addrs.len() > 0) and lsp.__type != "external") @@ -4445,7 +4445,7 @@ for (&Router(._uuid = lr_uuid)) { for (&RouterPort(.lrp = lrp, .json_name = json_name, .networks = lrp_networks, - .router = &router, + .router = router, .is_redirect = is_redirect) /* Drop packets from disabled logical ports (since logical flow * tables are default-drop). */ @@ -4649,7 +4649,7 @@ for (RouterPortNetworksIPv4Addr(rp@&RouterPort{.router = router}, addr)) { /* Logical router ingress table IP_INPUT: IP Input. */ -for (router in &Router(._uuid = lr_uuid, .mcast_cfg = &mcast_cfg)) { +for (router in &Router(._uuid = lr_uuid, .mcast_cfg = mcast_cfg)) { /* L3 admission control: drop multicast and broadcast source, localhost * source or destination, and zero network source or destination * (priority 100). */ @@ -4767,7 +4767,7 @@ function format_v6_networks(networks: lport_addresses): string = relation AddChassisResidentCheck_(lrp: uuid, add_check: bool) AddChassisResidentCheck_(lrp._uuid, res) :- - &SwitchPort(.peer = Some{&RouterPort{.lrp = lrp, .router = &router, .is_redirect = is_redirect}}, + &SwitchPort(.peer = Some{&RouterPort{.lrp = lrp, .router = router, .is_redirect = is_redirect}}, .sw = sw), router.l3dgw_port.is_some(), not sw.localnet_ports.is_empty(), @@ -4802,7 +4802,7 @@ AddChassisResidentCheck(lrp, false) :- /* Logical router ingress table IP_INPUT: IP Input for IPv4. */ -for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp) +for (&RouterPort(.router = router, .networks = networks, .lrp = lrp) if (not networks.ipv4_addrs.is_empty())) { /* L3 admission control: drop packets that originate from an @@ -5213,7 +5213,7 @@ Flow(.logical_datapath = rp.router._uuid, var ipv6_addr = FlatMap(rp.networks.ipv6_addrs). /* Logical router ingress table IP_INPUT: IP Input for IPv6. */ -for (&RouterPort(.router = &router, .networks = networks, .lrp = lrp) +for (&RouterPort(.router = router, .networks = networks, .lrp = lrp) if (not networks.ipv6_addrs.is_empty())) { //if (op->derived) { @@ -5329,7 +5329,7 @@ for (RouterPortNetworksIPv6Addr( } /* ICMPv6 time exceeded */ -for (RouterPortNetworksIPv6Addr(.port = &RouterPort{.router = &router, +for (RouterPortNetworksIPv6Addr(.port = &RouterPort{.router = router, .lrp = lrp, .json_name = json_name}, .addr = addr) @@ -6219,7 +6219,7 @@ function copy_ra_to_sb(port: RouterPort, address_mode: string): Map X-Patchwork-Id: 1459085 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fwX5KLRz9sCD for ; Sat, 27 Mar 2021 11:34:04 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id C2B9D419FB; Sat, 27 Mar 2021 00:34:02 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UiqMK9psbp9m; Sat, 27 Mar 2021 00:33:54 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTP id E5AFE4196F; Sat, 27 Mar 2021 00:33:35 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id B8CB2C000B; Sat, 27 Mar 2021 00:33:35 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 05798C000A for ; Sat, 27 Mar 2021 00:33:35 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 6F3DB60E21 for ; Sat, 27 Mar 2021 00:32:37 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zQdKcRbAUnky for ; Sat, 27 Mar 2021 00:32:34 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp3.osuosl.org (Postfix) with ESMTPS id 627B760DEA for ; Sat, 27 Mar 2021 00:32:25 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 9F018FF802; Sat, 27 Mar 2021 00:32:22 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:43 -0700 Message-Id: <20210327003147.2955790-18-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 17/21] ovn-northd-ddlog: Intern selected input relations. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk DDlog 0.38.0 adds the `--intern-table` CLI flag to the `ovsdb2ddlog` compiler to declare input tables coming from OVSDB as `Intern<...>`. This is useful for tables whose records are copied around as a whole and can therefore benefit from interning performance- and memory-wise. In the past we had to create separate tables in `helpers.dl` and copy records from the original input table to them while wrapping them in `Intern<>`. With this change, we avoid the extra copy and intern records as we ingest them for selected tables. We use the `--intern-table` flag to eliminate all intermediate tables in `helpers.dl`. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/helpers.dl | 36 ------------------------------------ northd/lrouter.dl | 12 ++++++------ northd/lswitch.dl | 26 +++++++++++++------------- northd/ovn-nb.dlopts | 8 ++++++++ northd/ovn-sb.dlopts | 1 + northd/ovn_northd.dl | 30 +++++++++++++++--------------- northd/ovsdb2ddlog2c | 6 +++--- 7 files changed, 46 insertions(+), 73 deletions(-) diff --git a/northd/helpers.dl b/northd/helpers.dl index 49281fcafc9a..33a8d15d8b32 100644 --- a/northd/helpers.dl +++ b/northd/helpers.dl @@ -20,42 +20,6 @@ import ovn output relation Warning[string] -/* ACLRef: reference to nb::ACL */ -relation ACLRef[Intern] -ACLRef[acl.intern()] :- nb::ACL[acl]. - -/* DHCP_Options: reference to nb::DHCP_Options */ -relation DHCP_OptionsRef[Intern] -DHCP_OptionsRef[options.intern()] :- nb::DHCP_Options[options]. - -/* QoS: reference to nb::QoS */ -relation QoSRef[Intern] -QoSRef[qos.intern()] :- nb::QoS[qos]. - -/* LoadBalancerRef: reference to nb::Load_Balancer */ -relation LoadBalancerRef[Intern] -LoadBalancerRef[lb.intern()] :- nb::Load_Balancer[lb]. - -/* LoadBalancerHealthCheckRef: reference to nb::Load_Balancer_Health_Check */ -relation LoadBalancerHealthCheckRef[Intern] -LoadBalancerHealthCheckRef[lbhc.intern()] :- nb::Load_Balancer_Health_Check[lbhc]. - -/* MeterRef: reference to nb::Meter*/ -relation MeterRef[Intern] -MeterRef[meter.intern()] :- nb::Meter[meter]. - -/* NATRef: reference to nb::NAT*/ -relation NATRef[Intern] -NATRef[nat.intern()] :- nb::NAT[nat]. - -/* AddressSetRef: reference to nb::Address_Set */ -relation AddressSetRef[Intern] -AddressSetRef[__as.intern()] :- nb::Address_Set[__as]. - -/* ServiceMonitor: reference to sb::Service_Monitor */ -relation ServiceMonitorRef[Intern] -ServiceMonitorRef[sm.intern()] :- sb::Service_Monitor[sm]. - /* Switch-to-router logical port connections */ relation SwitchRouterPeer(lsp: uuid, lsp_name: string, lrp: uuid) SwitchRouterPeer(lsp, lsp_name, lrp) :- diff --git a/northd/lrouter.dl b/northd/lrouter.dl index 23d320be6cc7..c51f0fbe6c44 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -281,7 +281,7 @@ relation LogicalRouterNAT0( LogicalRouterNAT0(lr, nat, external_ip, external_mac) :- nb::Logical_Router(._uuid = lr, .nat = nats), var nat_uuid = FlatMap(nats), - nat in &NATRef[nb::NAT{._uuid = nat_uuid}], + nat in &nb::NAT(._uuid = nat_uuid), Some{var external_ip} = ip46_parse(nat.external_ip), var external_mac = match (nat.external_mac) { Some{s} -> eth_addr_from_string(s), @@ -290,12 +290,12 @@ LogicalRouterNAT0(lr, nat, external_ip, external_mac) :- Warning["Bad ip address ${nat.external_ip} in nat configuration for router ${lr_name}."] :- nb::Logical_Router(._uuid = lr, .nat = nats, .name = lr_name), var nat_uuid = FlatMap(nats), - nat in &NATRef[nb::NAT{._uuid = nat_uuid}], + nat in &nb::NAT(._uuid = nat_uuid), None = ip46_parse(nat.external_ip). Warning["Bad MAC address ${s} in nat configuration for router ${lr_name}."] :- nb::Logical_Router(._uuid = lr, .nat = nats, .name = lr_name), var nat_uuid = FlatMap(nats), - nat in &NATRef[nb::NAT{._uuid = nat_uuid}], + nat in &nb::NAT(._uuid = nat_uuid), Some{var s} = nat.external_mac, None = eth_addr_from_string(s). @@ -308,12 +308,12 @@ LogicalRouterNAT(lr, NAT{nat, external_ip, external_mac, Some{AllowedExtIps{__as LogicalRouterNAT0(lr, nat, external_ip, external_mac), nat.exempted_ext_ips == None, Some{var __as_uuid} = nat.allowed_ext_ips, - __as in &AddressSetRef[nb::Address_Set{._uuid = __as_uuid}]. + __as in &nb::Address_Set(._uuid = __as_uuid). LogicalRouterNAT(lr, NAT{nat, external_ip, external_mac, Some{ExemptedExtIps{__as}}}) :- LogicalRouterNAT0(lr, nat, external_ip, external_mac), nat.allowed_ext_ips == None, Some{var __as_uuid} = nat.exempted_ext_ips, - __as in &AddressSetRef[nb::Address_Set{._uuid = __as_uuid}]. + __as in &nb::Address_Set(._uuid = __as_uuid). Warning["NAT rule: ${nat._uuid} not applied, since" "both allowed and exempt external ips set"] :- LogicalRouterNAT0(lr, nat, _, _), @@ -404,7 +404,7 @@ relation LogicalRouterLB(lr: uuid, nat: Intern) LogicalRouterLB(lr, lb) :- nb::Logical_Router(._uuid = lr, .load_balancer = lbs), var lb_uuid = FlatMap(lbs), - lb in &LoadBalancerRef[nb::Load_Balancer{._uuid = lb_uuid}]. + lb in &nb::Load_Balancer(._uuid = lb_uuid). relation LogicalRouterLBs(lr: uuid, nat: Vec>) diff --git a/northd/lswitch.dl b/northd/lswitch.dl index df74a3731c1d..f1456366f3cb 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -113,7 +113,7 @@ relation LogicalSwitchStatefulACL(ls: uuid, acl: uuid) LogicalSwitchStatefulACL(ls, acl) :- LogicalSwitchACL(ls, acl), - nb::ACL(._uuid = acl, .action = "allow-related"). + &nb::ACL(._uuid = acl, .action = "allow-related"). relation LogicalSwitchHasStatefulACL(ls: uuid, has_stateful_acl: bool) @@ -280,7 +280,7 @@ relation SwitchLB(sw_uuid: uuid, lb: Intern) SwitchLB(sw_uuid, lb) :- nb::Logical_Switch(._uuid = sw_uuid, .load_balancer = lb_ids), var lb_id = FlatMap(lb_ids), - lb in &LoadBalancerRef[nb::Load_Balancer{._uuid = lb_id}]. + lb in &nb::Load_Balancer(._uuid = lb_id). /* Load balancer VIPs associated with switch */ relation SwitchLBVIP(sw_uuid: uuid, lb: Intern, vip: string, backends: string) @@ -309,10 +309,10 @@ relation LBVIP0( backend_ips: string, health_check: Intern) LBVIP0(lb, vip_key, backend_ips, health_check) :- - LoadBalancerRef[lb], + lb in &nb::Load_Balancer(), var vip = FlatMap(lb.vips), (var vip_key, var backend_ips) = vip, - LoadBalancerHealthCheckRef[health_check@&nb::Load_Balancer_Health_Check{.vip = vip_key}], + health_check in &nb::Load_Balancer_Health_Check(.vip = vip_key), lb.health_check.contains(health_check._uuid). relation LBVIP1( @@ -323,7 +323,7 @@ relation LBVIP1( LBVIP1(lb, vip_key, backend_ips, Some{health_check}) :- LBVIP0(lb, vip_key, backend_ips, health_check). LBVIP1(lb, vip_key, backend_ips, None) :- - LoadBalancerRef[lb], + lb in &nb::Load_Balancer(), var vip = FlatMap(lb.vips), (var vip_key, var backend_ips) = vip, not LBVIP0(lb, vip_key, backend_ips, _). @@ -434,7 +434,7 @@ LBVIPBackendStatus0(lbvip, backend, is_online(sm.status)) :- LBVIP[lbvip@&LBVIP{.lb = lb}], var backend = FlatMap(lbvip.backends), Some{var svc_monitor} = backend.svc_monitor, - sm in sb::Service_Monitor(.port = backend.port as integer), + sm in &sb::Service_Monitor(.port = backend.port as integer), ip46_parse(sm.ip) == Some{backend.ip}, svc_monitor.port_name == sm.logical_port, default_protocol(lb.protocol) == default_protocol(sm.protocol). @@ -458,7 +458,7 @@ SwitchPortDHCPv4Options(port, options) :- port in &SwitchPort(.lsp = lsp), port.lsp.__type != "external", Some{var dhcpv4_uuid} = lsp.dhcpv4_options, - options in &DHCP_OptionsRef[nb::DHCP_Options{._uuid = dhcpv4_uuid}]. + options in &nb::DHCP_Options(._uuid = dhcpv4_uuid). /* SwitchPortDHCPv6Options: many-to-one relation between logical switches and DHCPv4 options */ relation SwitchPortDHCPv6Options( @@ -469,7 +469,7 @@ SwitchPortDHCPv6Options(port, options) :- port in &SwitchPort(.lsp = lsp), port.lsp.__type != "external", Some{var dhcpv6_uuid} = lsp.dhcpv6_options, - options in &DHCP_OptionsRef[nb::DHCP_Options{._uuid = dhcpv6_uuid}]. + options in &nb::DHCP_Options(._uuid = dhcpv6_uuid). /* SwitchQoS: many-to-one relation between logical switches and nb::QoS */ relation SwitchQoS(sw: Intern, qos: Intern) @@ -478,7 +478,7 @@ SwitchQoS(sw, qos) :- sw in &Switch(), nb::Logical_Switch(._uuid = sw._uuid, .qos_rules = qos_rules), var qos_rule = FlatMap(qos_rules), - qos in &QoSRef[nb::QoS{._uuid = qos_rule}]. + qos in &nb::QoS(._uuid = qos_rule). /* Reports whether a given ACL is associated with a fair meter. * 'has_fair_meter' is false if 'acl' has no meter, or if has a meter @@ -489,14 +489,14 @@ relation ACLHasFairMeter(acl: Intern, has_fair_meter: bool) ACLHasFairMeter(acl, true) :- ACLWithFairMeter(acl, _). ACLHasFairMeter(acl, false) :- - acl in &ACLRef[_], + acl in &nb::ACL(), not ACLWithFairMeter(acl, _). /* All the ACLs associated with a fair meter, with their fair meters. */ relation ACLWithFairMeter(acl: Intern, meter: Intern) ACLWithFairMeter(acl, meter) :- - acl in &ACLRef[nb::ACL{.meter = Some{meter_name}}], - meter in &MeterRef[nb::Meter{.name = meter_name, .fair = Some{true}}]. + acl in &nb::ACL(.meter = Some{meter_name}), + meter in &nb::Meter(.name = meter_name, .fair = Some{true}). /* SwitchACL: many-to-many relation between logical switches and ACLs */ relation &SwitchACL(sw: Intern, @@ -506,7 +506,7 @@ relation &SwitchACL(sw: Intern, &SwitchACL(.sw = sw, .acl = acl, .has_fair_meter = has_fair_meter) :- LogicalSwitchACL(sw_uuid, acl_uuid), sw in &Switch(._uuid = sw_uuid), - acl in &ACLRef[nb::ACL{._uuid = acl_uuid}], + acl in &nb::ACL(._uuid = acl_uuid), ACLHasFairMeter(acl, has_fair_meter). function oVN_FEATURE_PORT_UP_NOTIF(): string { "port-up-notif" } diff --git a/northd/ovn-nb.dlopts b/northd/ovn-nb.dlopts index c9c171fe1c84..c4390c904f33 100644 --- a/northd/ovn-nb.dlopts +++ b/northd/ovn-nb.dlopts @@ -13,3 +13,11 @@ --rw NB_Global.ipsec --rw NB_Global.nb_cfg_timestamp --rw NB_Global.hv_cfg_timestamp +--intern-table DHCP_Options +--intern-table ACL +--intern-table QoS +--intern-table Load_Balancer +--intern-table Load_Balancer_Health_Check +--intern-table Meter +--intern-table NAT +--intern-table Address_Set diff --git a/northd/ovn-sb.dlopts b/northd/ovn-sb.dlopts index 1f99118a2b8d..ea4952758b80 100644 --- a/northd/ovn-sb.dlopts +++ b/northd/ovn-sb.dlopts @@ -30,3 +30,4 @@ --ro SB_Global.external_ids --ro SB_Global.ssl --ro Service_Monitor.status +--intern-table Service_Monitor diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 5476a6f2e85f..f4c6f6d1f62a 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -35,7 +35,7 @@ for (mb in nb::Meter_Band) { } /* Meter table */ -for (meter in nb::Meter) { +for (meter in &nb::Meter) { sb::Out_Meter(._uuid = meter._uuid, .name = meter.name, .unit = meter.unit, @@ -704,7 +704,7 @@ CheckLspIsUp[true] :- sb::Out_Address_Set(._uuid = nb_as._uuid, .name = nb_as.name, .addresses = nb_as.addresses) :- - AddressSetRef[nb_as]. + nb_as in &nb::Address_Set(). sb::Out_Address_Set(._uuid = hash128("svc_monitor_mac"), .name = "svc_monitor_mac", @@ -715,7 +715,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, pg_ip4addrs.union()) :- PortGroupPort(.pg_name = pg_name, .port = port_uuid), var as_name = pg_name ++ "_ip4", // avoid name collisions with user-defined Address_Sets - not nb::Address_Set(.name = as_name), + not &nb::Address_Set(.name = as_name), PortStaticAddresses(.lsport = port_uuid, .ip4addrs = stat), SwitchPortNewDynamicAddress(&SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = port_uuid}}, dyn_addr), @@ -734,13 +734,13 @@ sb::Out_Address_Set(hash128(as_name), as_name, set_empty()) :- nb::Port_Group(.ports = set_empty(), .name = pg_name), var as_name = pg_name ++ "_ip4", // avoid name collisions with user-defined Address_Sets - not nb::Address_Set(.name = as_name). + not &nb::Address_Set(.name = as_name). sb::Out_Address_Set(hash128(as_name), as_name, pg_ip6addrs.union()) :- PortGroupPort(.pg_name = pg_name, .port = port_uuid), var as_name = pg_name ++ "_ip6", // avoid name collisions with user-defined Address_Sets - not nb::Address_Set(.name = as_name), + not &nb::Address_Set(.name = as_name), PortStaticAddresses(.lsport = port_uuid, .ip6addrs = stat), SwitchPortNewDynamicAddress(&SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = port_uuid}}, dyn_addr), @@ -759,7 +759,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, set_empty()) :- nb::Port_Group(.ports = set_empty(), .name = pg_name), var as_name = pg_name ++ "_ip6", // avoid name collisions with user-defined Address_Sets - not nb::Address_Set(.name = as_name). + not &nb::Address_Set(.name = as_name). /* * Port_Group @@ -1993,11 +1993,11 @@ if (lsp.__type == "router" or lsp.__type == "localnet") { relation HasEventElbMeter(has_meter: bool) HasEventElbMeter(true) :- - nb::Meter(.name = "event-elb"). + &nb::Meter(.name = "event-elb"). HasEventElbMeter(false) :- Unit(), - not nb::Meter(.name = "event-elb"). + not &nb::Meter(.name = "event-elb"). /* Empty LoadBalancer Controller event */ function build_empty_lb_event_flow(key: string, lb: Intern, @@ -2049,7 +2049,7 @@ relation LoadBalancerEmptyEvents(lb: Intern) LoadBalancerEmptyEvents(lb) :- nb::NB_Global(.options = global_options), var global_events = global_options.get_bool_def("controller_event", false), - lb in &LoadBalancerRef[nb::Load_Balancer{.options = local_options}], + lb in &nb::Load_Balancer(.options = local_options), var local_events = local_options.get_bool_def("event", false), global_events or local_events. @@ -2659,7 +2659,7 @@ for (SwitchPortDHCPv6Options(.port = &SwitchPort{.lsp = lsp, .sw = sw}, relation QoSAction(qos: uuid, key_action: string, value_action: integer) QoSAction(qos, k, v) :- - nb::QoS(._uuid = qos, .action = actions), + &nb::QoS(._uuid = qos, .action = actions), var action = FlatMap(actions), (var k, var v) = action. @@ -3420,7 +3420,7 @@ Flow(.logical_datapath = sp.sw._uuid, function build_dhcpv4_action( lsp_json_key: string, - dhcpv4_options: nb::DHCP_Options, + dhcpv4_options: Intern, offer_ip: in_addr) : Option<(string, string, string)> = { match (ip_parse_masked(dhcpv4_options.cidr)) { @@ -3478,7 +3478,7 @@ function build_dhcpv4_action( function build_dhcpv6_action( lsp_json_key: string, - dhcpv6_options: nb::DHCP_Options, + dhcpv6_options: Intern, offer_ip: in6_addr): Option<(string, string)> = { match (ipv6_parse_masked(dhcpv6_options.cidr)) { @@ -3605,7 +3605,7 @@ for (lsp in &SwitchPort /* DHCPv4 options enabled for this port */ Some{var dhcpv4_options_uuid} = lsp.lsp.dhcpv4_options in { - for (dhcpv4_options in nb::DHCP_Options(._uuid = dhcpv4_options_uuid)) { + for (dhcpv4_options in &nb::DHCP_Options(._uuid = dhcpv4_options_uuid)) { for (SwitchPortIPv4Address(.port = &SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = lsp.lsp._uuid}}, .ea = ea, .addr = addr)) { Some{(var options_action, var response_action, var ipv4_addr_match)} = build_dhcpv4_action(json_key, dhcpv4_options, addr.addr) in @@ -3662,7 +3662,7 @@ for (lsp in &SwitchPort /* DHCPv6 options enabled for this port */ Some{var dhcpv6_options_uuid} = lsp.lsp.dhcpv6_options in { - for (dhcpv6_options in nb::DHCP_Options(._uuid = dhcpv6_options_uuid)) { + for (dhcpv6_options in &nb::DHCP_Options(._uuid = dhcpv6_options_uuid)) { for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = lsp.lsp._uuid}}, .ea = ea, .addr = addr)) { Some{(var options_action, var response_action)} = build_dhcpv6_action(json_key, dhcpv6_options, addr.addr) in @@ -7745,7 +7745,7 @@ sb::Out_Load_Balancer(._uuid = lb._uuid, nb in nb::Logical_Switch(._uuid = ls_uuid, .load_balancer = lb_uuids), var lb_uuid = FlatMap(lb_uuids), var datapaths = ls_uuid.group_by(lb_uuid).to_set(), - lb in nb::Load_Balancer(._uuid = lb_uuid), + lb in &nb::Load_Balancer(._uuid = lb_uuid), /* Store the fact that northd provides the original (destination IP + * transport port) tuple. */ diff --git a/northd/ovsdb2ddlog2c b/northd/ovsdb2ddlog2c index c66ad81073e1..19aeb265b633 100755 --- a/northd/ovsdb2ddlog2c +++ b/northd/ovsdb2ddlog2c @@ -36,6 +36,7 @@ The following ovsdb2ddlog options are supported: --output-only-table=TABLE Mark TABLE as output-only. DDlog will send updates to this table directly to OVSDB without comparing it with current OVSDB state. --ro=TABLE.COLUMN Ignored. --rw=TABLE.COLUMN Ignored. + --intern-table=TABLE Ignored. --output-file=FILE.inc Write output to FILE.inc. If this option is not specified, output will be written to stdout. The following options are also available: @@ -52,6 +53,7 @@ if __name__ == "__main__": 'schema-file=', 'output-table=', 'output-only-table=', + 'intern-table=', 'ro=', 'rw=', 'output-file=']) @@ -75,9 +77,7 @@ if __name__ == "__main__": schema_file = value elif key in ['-o', '--output-table']: output_tables.add(value) - elif key == '--output-only-table': - output_only_tables.add(value) - elif key in ['--ro', '--rw']: + elif key in ['--ro', '--rw', '--intern-table']: pass elif key == '--output-file': output_file = value From patchwork Sat Mar 27 00:31:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459084 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fwM4Qnfz9sCD for ; Sat, 27 Mar 2021 11:33:55 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 36D6984E4C; Sat, 27 Mar 2021 00:33:53 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id zHFqkQRoV4rX; Sat, 27 Mar 2021 00:33:48 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTP id 475AD84E13; Sat, 27 Mar 2021 00:33:25 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 18740C000D; Sat, 27 Mar 2021 00:33:25 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1F0F4C000B for ; Sat, 27 Mar 2021 00:33:23 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 929BD84DC6 for ; Sat, 27 Mar 2021 00:32:42 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id t0bz5o4G4J1d for ; Sat, 27 Mar 2021 00:32:37 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id 00E2084DF1 for ; Sat, 27 Mar 2021 00:32:26 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 4C995FF805; Sat, 27 Mar 2021 00:32:24 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:44 -0700 Message-Id: <20210327003147.2955790-19-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 18/21] ovn-northd-ddlog: Intern nb::Logical_Router_Port. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Use the `--intern-table` switch to intern `Logical_Router_Port` records, so that they can be copied and compared efficiently by pointer. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/helpers.dl | 2 +- northd/lrouter.dl | 50 ++++++++++++++++++++++---------------------- northd/lswitch.dl | 2 +- northd/multicast.dl | 2 +- northd/ovn-nb.dlopts | 1 + northd/ovn_northd.dl | 34 +++++++++++++++--------------- 6 files changed, 46 insertions(+), 45 deletions(-) diff --git a/northd/helpers.dl b/northd/helpers.dl index 33a8d15d8b32..820e37bb3072 100644 --- a/northd/helpers.dl +++ b/northd/helpers.dl @@ -25,7 +25,7 @@ relation SwitchRouterPeer(lsp: uuid, lsp_name: string, lrp: uuid) SwitchRouterPeer(lsp, lsp_name, lrp) :- nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = "router", .options = options), Some{var router_port} = options.get("router-port"), - nb::Logical_Router_Port(.name = router_port, ._uuid = lrp). + &nb::Logical_Router_Port(.name = router_port, ._uuid = lrp). function get_bool_def(m: Map, k: string, def: bool): bool = { m.get(k) diff --git a/northd/lrouter.dl b/northd/lrouter.dl index c51f0fbe6c44..81e4a03e8a91 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -21,7 +21,7 @@ import helpers import lswitch function is_enabled(lr: nb::Logical_Router): bool { is_enabled(lr.enabled) } -function is_enabled(lrp: nb::Logical_Router_Port): bool { is_enabled(lrp.enabled) } +function is_enabled(lrp: Intern): bool { is_enabled(lrp.enabled) } function is_enabled(rp: RouterPort): bool { rp.lrp.is_enabled() } function is_enabled(rp: Intern): bool { rp.lrp.is_enabled() } @@ -42,7 +42,7 @@ Warning[message] :- LogicalRouterPortCandidate(lrp_uuid, lr_uuid), var lrs = lr_uuid.group_by(lrp_uuid).to_set(), lrs.size() > 1, - lrp in nb::Logical_Router_Port(._uuid = lrp_uuid), + lrp in &nb::Logical_Router_Port(._uuid = lrp_uuid), var message = "Bad configuration: logical router port ${lrp.name} belongs " "to more than one logical router". @@ -69,9 +69,9 @@ LogicalRouterPort(lrp_uuid, lr_uuid) :- relation PeerLogicalRouter(a: uuid, b: uuid) PeerLogicalRouter(lrp_uuid, peer._uuid) :- LogicalRouterPort(lrp_uuid, _), - lrp in nb::Logical_Router_Port(._uuid = lrp_uuid), + lrp in &nb::Logical_Router_Port(._uuid = lrp_uuid), Some{var peer_name} = lrp.peer, - peer in nb::Logical_Router_Port(.name = peer_name), + peer in &nb::Logical_Router_Port(.name = peer_name), peer.peer == Some{lrp.name}, // 'peer' must point back to 'lrp' lrp_uuid != peer._uuid. // No reflexive pointers. @@ -86,7 +86,7 @@ PeerLogicalRouter(lrp_uuid, peer._uuid) :- relation FirstHopLogicalRouter(lrouter: uuid, lswitch: uuid) FirstHopLogicalRouter(lrouter, lswitch) :- LogicalRouterPort(lrp_uuid, lrouter), - lrp in nb::Logical_Router_Port(._uuid = lrp_uuid, .peer = None), + lrp in &nb::Logical_Router_Port(._uuid = lrp_uuid, .peer = None), LogicalSwitchRouterPort(lsp_uuid, lrp.name, lswitch). relation LogicalSwitchRouterPort(lsp: uuid, lsp_router_port: string, ls: uuid) @@ -119,7 +119,7 @@ ReachableLogicalRouter(a, a) :- ReachableLogicalRouter(a, _). // ha_chassis_group and gateway_chassis may not both be present. Warning[message] :- - lrp in nb::Logical_Router_Port(), + lrp in &nb::Logical_Router_Port(), lrp.ha_chassis_group.is_some(), not lrp.gateway_chassis.is_empty(), var message = "Both ha_chassis_group and gateway_chassis configured on " @@ -127,7 +127,7 @@ Warning[message] :- // A distributed gateway port cannot also be an L3 gateway router. Warning[message] :- - lrp in nb::Logical_Router_Port(), + lrp in &nb::Logical_Router_Port(), lrp.ha_chassis_group.is_some() or not lrp.gateway_chassis.is_empty(), lrp.options.contains_key("chassis"), var message = "Bad configuration: distributed gateway port configured on " @@ -143,7 +143,7 @@ relation DistributedGatewayPortCandidate(lr_uuid: uuid, lrp_uuid: uuid) DistributedGatewayPortCandidate(lr_uuid, lrp_uuid) :- lr in nb::Logical_Router(._uuid = lr_uuid), LogicalRouterPort(lrp_uuid, lr._uuid), - lrp in nb::Logical_Router_Port(._uuid = lrp_uuid), + lrp in &nb::Logical_Router_Port(._uuid = lrp_uuid), not lrp.options.contains_key("chassis"), var has_hcg = lrp.ha_chassis_group.is_some(), var has_gc = not lrp.gateway_chassis.is_empty(), @@ -161,13 +161,13 @@ Warning[message] :- * Each row means 'lrp' is the distributed gateway port on 'lr_uuid'. * * There is at most one distributed gateway port per logical router. */ -relation DistributedGatewayPort(lrp: nb::Logical_Router_Port, lr_uuid: uuid) +relation DistributedGatewayPort(lrp: Intern, lr_uuid: uuid) DistributedGatewayPort(lrp, lr_uuid) :- DistributedGatewayPortCandidate(lr_uuid, lrp_uuid), var lrps = lrp_uuid.group_by(lr_uuid).to_set(), lrps.size() == 1, Some{var lrp_uuid} = lrps.nth(0), - lrp in nb::Logical_Router_Port(._uuid = lrp_uuid). + lrp in &nb::Logical_Router_Port(._uuid = lrp_uuid). /* HAChassis is an abstraction over nb::Gateway_Chassis and nb::HA_Chassis, which * are different ways to represent the same configuration. Each row is @@ -249,12 +249,12 @@ LogicalRouterHAChassisGroup(lr_uuid, /* For each router port, tracks whether it's a redirect port of its router */ relation RouterPortIsRedirect(lrp: uuid, is_redirect: bool) -RouterPortIsRedirect(lrp, true) :- DistributedGatewayPort(nb::Logical_Router_Port{._uuid = lrp}, _). +RouterPortIsRedirect(lrp, true) :- DistributedGatewayPort(&nb::Logical_Router_Port{._uuid = lrp}, _). RouterPortIsRedirect(lrp, false) :- - nb::Logical_Router_Port(._uuid = lrp), - not DistributedGatewayPort(nb::Logical_Router_Port{._uuid = lrp}, _). + &nb::Logical_Router_Port(._uuid = lrp), + not DistributedGatewayPort(&nb::Logical_Router_Port{._uuid = lrp}, _). -relation LogicalRouterRedirectPort(lr: uuid, has_redirect_port: Option) +relation LogicalRouterRedirectPort(lr: uuid, has_redirect_port: Option>) LogicalRouterRedirectPort(lr, Some{lrp}) :- DistributedGatewayPort(lrp, lr). @@ -443,7 +443,7 @@ typedef Router = Router { external_ids: Map, /* Additional computed fields. */ - l3dgw_port: Option, + l3dgw_port: Option>, redirect_port_name: string, is_gateway: bool, nats: Vec, @@ -513,9 +513,9 @@ RouterLBVIP(router, lb, vip, backends) :- relation RouterRouterPeer(rport1: uuid, rport2: uuid, rport2_name: string) RouterRouterPeer(rport1, rport2, peer_name) :- - nb::Logical_Router_Port(._uuid = rport1, .peer = peer), + &nb::Logical_Router_Port(._uuid = rport1, .peer = peer), Some{var peer_name} = peer, - nb::Logical_Router_Port(._uuid = rport2, .name = peer_name). + &nb::Logical_Router_Port(._uuid = rport2, .name = peer_name). /* Router port can peer with anothe router port, a switch port or have * no peer. @@ -542,7 +542,7 @@ RouterPortPeer(rport1, PeerRouter{rport2, rport2_name}) :- RouterRouterPeer(rport1, rport2, rport2_name). RouterPortPeer(rport, PeerNone) :- - nb::Logical_Router_Port(._uuid = rport), + &nb::Logical_Router_Port(._uuid = rport), not SwitchRouterPeer(_, _, rport), not RouterRouterPeer(rport, _, _). @@ -553,7 +553,7 @@ RouterPortPeer(rport, PeerNone) :- * faster convergence.) */ relation RouterPortSbOptions(lrp_uuid: uuid, options: Map) RouterPortSbOptions(lrp._uuid, options) :- - lrp in nb::Logical_Router_Port(), + lrp in &nb::Logical_Router_Port(), pb in sb::Port_Binding(._uuid = lrp._uuid), var options = { var options = pb.options; @@ -562,21 +562,21 @@ RouterPortSbOptions(lrp._uuid, options) :- options }. RouterPortSbOptions(lrp._uuid, map_empty()) :- - lrp in nb::Logical_Router_Port(), + lrp in &nb::Logical_Router_Port(), not sb::Port_Binding(._uuid = lrp._uuid). relation RouterPortHasBfd(lrp_uuid: uuid, has_bfd: bool) RouterPortHasBfd(lrp_uuid, true) :- - nb::Logical_Router_Port(._uuid = lrp_uuid, .name = logical_port), + &nb::Logical_Router_Port(._uuid = lrp_uuid, .name = logical_port), nb::BFD(.logical_port = logical_port). RouterPortHasBfd(lrp_uuid, false) :- - nb::Logical_Router_Port(._uuid = lrp_uuid, .name = logical_port), + &nb::Logical_Router_Port(._uuid = lrp_uuid, .name = logical_port), not nb::BFD(.logical_port = logical_port). /* FIXME: what should happen when extract_lrp_networks fails? */ /* RouterPort relation collects all attributes of a logical router port */ typedef RouterPort = RouterPort { - lrp: nb::Logical_Router_Port, + lrp: Intern, json_name: string, networks: lport_addresses, router: Intern, @@ -600,7 +600,7 @@ RouterPort[RouterPort{ .sb_options = sb_options, .has_bfd = has_bfd }.intern()] :- - nb::Logical_Router_Port[lrp], + lrp in &nb::Logical_Router_Port(), Some{var networks} = extract_lrp_networks(lrp.mac, lrp.networks), LogicalRouterPort(lrp._uuid, lrouter_uuid), router in &Router(._uuid = lrouter_uuid), @@ -765,7 +765,7 @@ RouterStaticRoute(router, key, dsts) :- .output_port = Some{oport}, .ecmp_symmetric_reply = ecmp_symmetric_reply), /* output_port specified */ - port in &RouterPort(.lrp = nb::Logical_Router_Port{.name = oport}, + port in &RouterPort(.lrp = &nb::Logical_Router_Port{.name = oport}, .networks = networks), Some{var src_ip} = match (find_lrp_member_ip(networks, nexthop)) { Some{src_ip} -> Some{src_ip}, diff --git a/northd/lswitch.dl b/northd/lswitch.dl index f1456366f3cb..7a49ac17dbab 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -30,7 +30,7 @@ relation SwitchRouterPeerRef(lsp: uuid, rport: Option>) SwitchRouterPeerRef(lsp, Some{rport}) :- SwitchRouterPeer(lsp, _, lrp), - rport in &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp}). + rport in &RouterPort(.lrp = &nb::Logical_Router_Port{._uuid = lrp}). SwitchRouterPeerRef(lsp, None) :- nb::Logical_Switch_Port(._uuid = lsp), diff --git a/northd/multicast.dl b/northd/multicast.dl index 25fcd2938f6b..bd9bc9b46f61 100644 --- a/northd/multicast.dl +++ b/northd/multicast.dl @@ -101,7 +101,7 @@ McastPortCfg[McastPortCfg{lsp_uuid, false, flood, flood_reports}.intern()] :- var flood_reports = options.get_bool_def("mcast_flood_reports", false). McastPortCfg[McastPortCfg{lrp_uuid, true, flood, flood}.intern()] :- - nb::Logical_Router_Port(._uuid = lrp_uuid, .options = options), + &nb::Logical_Router_Port(._uuid = lrp_uuid, .options = options), var flood = options.get_bool_def("mcast_flood", false). /* Mapping between Switch and the set of router port uuids on which to flood diff --git a/northd/ovn-nb.dlopts b/northd/ovn-nb.dlopts index c4390c904f33..c1ceb4f1496a 100644 --- a/northd/ovn-nb.dlopts +++ b/northd/ovn-nb.dlopts @@ -21,3 +21,4 @@ --intern-table Meter --intern-table NAT --intern-table Address_Set +--intern-table Logical_Router_Port diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index f4c6f6d1f62a..045a054105bc 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -410,7 +410,7 @@ relation RouterPortRAOptionsComplete(lrp: uuid, options: Map) RouterPortRAOptionsComplete(lrp, options) :- RouterPortRAOptions(lrp, options). RouterPortRAOptionsComplete(lrp, map_empty()) :- - nb::Logical_Router_Port(._uuid = lrp), + &nb::Logical_Router_Port(._uuid = lrp), not RouterPortRAOptions(lrp, _). @@ -1375,7 +1375,7 @@ nb::Out_Logical_Switch_Port(._uuid = lsp._uuid, relation LRPIPv6Prefix0(lrp_uuid: uuid, ipv6_prefix: string) LRPIPv6Prefix0(lrp._uuid, ipv6_prefix) :- - lrp in nb::Logical_Router_Port(), + lrp in &nb::Logical_Router_Port(), lrp.options.get_bool_def("prefix", false), sb::Port_Binding(.logical_port = lrp.name, .options = options), Some{var ipv6_ra_pd_list} = options.get("ipv6_ra_pd_list"), @@ -1386,12 +1386,12 @@ relation LRPIPv6Prefix(lrp_uuid: uuid, ipv6_prefix: Option) LRPIPv6Prefix(lrp_uuid, Some{ipv6_prefix}) :- LRPIPv6Prefix0(lrp_uuid, ipv6_prefix). LRPIPv6Prefix(lrp_uuid, None) :- - nb::Logical_Router_Port(._uuid = lrp_uuid), + &nb::Logical_Router_Port(._uuid = lrp_uuid), not LRPIPv6Prefix0(lrp_uuid, _). nb::Out_Logical_Router_Port(._uuid = _uuid, .ipv6_prefix = to_set(ipv6_prefix)) :- - nb::Logical_Router_Port(._uuid = _uuid, .name = name), + &nb::Logical_Router_Port(._uuid = _uuid, .name = name), LRPIPv6Prefix(_uuid, ipv6_prefix). typedef Pipeline = Ingress | Egress @@ -4797,7 +4797,7 @@ AddChassisResidentCheck(lrp, add_check) :- AddChassisResidentCheck_(lrp, add_check). AddChassisResidentCheck(lrp, false) :- - nb::Logical_Router_Port(._uuid = lrp), + &nb::Logical_Router_Port(._uuid = lrp), not AddChassisResidentCheck_(lrp, _). @@ -4890,7 +4890,7 @@ LogicalRouterPortNatArpNdFlow(router, nat, l3dgw_port) :- /* Respond to ARP/NS requests on the chassis that binds the gw * port. Drop the ARP/NS requests on other chassis. */ -relation LogicalRouterPortNatArpNdFlow(router: Intern, nat: NAT, lrp: nb::Logical_Router_Port) +relation LogicalRouterPortNatArpNdFlow(router: Intern, nat: NAT, lrp: Intern) LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, Some{extra_match}, false, 92), LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, None, true, 91) :- LogicalRouterPortNatArpNdFlow(router, nat, lrp), @@ -4923,7 +4923,7 @@ LogicalRouterArpNdFlow(router, nat, Some{lrp}, mac, None, true, 91) :- relation LogicalRouterArpNdFlow( router: Intern, nat: NAT, - lrp: Option, + lrp: Option>, mac: string, extra_match: Option, drop: bool, @@ -4939,7 +4939,7 @@ LogicalRouterNdFlow(router, lrp, "nd_na", ipv6, true, mac, extra_match, drop, pr relation LogicalRouterArpFlow( lr: Intern, - lrp: Option, + lrp: Option>, ip: in_addr, mac: string, extra_match: Option, @@ -4982,7 +4982,7 @@ Flow(.logical_datapath = lr._uuid, relation LogicalRouterNdFlow( lr: Intern, - lrp: Option, + lrp: Option>, action: string, ip: in6_addr, sn_ip: bool, @@ -5118,7 +5118,7 @@ Flow(.logical_datapath = lr_uuid, .__match = "ip4.dst == {" ++ match_ips.join(", ") ++ "}", .actions = "drop;", .external_ids = stage_hint(lrp_uuid)) :- - &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid}, + &RouterPort(.lrp = &nb::Logical_Router_Port{._uuid = lrp_uuid}, .router = &Router{.snat_ips = snat_ips, .force_lb_snat = false, ._uuid = lr_uuid}, @@ -5132,7 +5132,7 @@ Flow(.logical_datapath = lr_uuid, .__match = "ip6.dst == {" ++ match_ips.join(", ") ++ "}", .actions = "drop;", .external_ids = stage_hint(lrp_uuid)) :- - &RouterPort(.lrp = nb::Logical_Router_Port{._uuid = lrp_uuid}, + &RouterPort(.lrp = &nb::Logical_Router_Port{._uuid = lrp_uuid}, .router = &Router{.snat_ips = snat_ips, .force_lb_snat = false, ._uuid = lr_uuid}, @@ -6218,7 +6218,7 @@ function copy_ra_to_sb(port: RouterPort, address_mode: string): Map X-Patchwork-Id: 1459087 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fwh33HBz9sCD for ; Sat, 27 Mar 2021 11:34:12 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id F04AF40F7B; Sat, 27 Mar 2021 00:34:09 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id HgYIvEGA31GR; Sat, 27 Mar 2021 00:34:05 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp2.osuosl.org (Postfix) with ESMTP id F079540F0D; Sat, 27 Mar 2021 00:33:28 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A4EB4C000D; Sat, 27 Mar 2021 00:33:27 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0E841C000A for ; Sat, 27 Mar 2021 00:33:26 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 1F62084D6D for ; Sat, 27 Mar 2021 00:32:43 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id qlbC3FTQ0Cp1 for ; Sat, 27 Mar 2021 00:32:38 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp1.osuosl.org (Postfix) with ESMTPS id A059484DFA for ; Sat, 27 Mar 2021 00:32:28 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id F2CF4FF804; Sat, 27 Mar 2021 00:32:25 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:45 -0700 Message-Id: <20210327003147.2955790-20-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 19/21] ovn-northd-ddlog: Intern nb::Logical_Switch_Port. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk Use the `--intern-table` switch to intern `Logical_Switch_Port` records, so that they can be copied and compared efficiently by pointer. Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/helpers.dl | 2 +- northd/lrouter.dl | 2 +- northd/lswitch.dl | 28 ++++++++++++++-------------- northd/multicast.dl | 6 +++--- northd/ovn-nb.dlopts | 1 + northd/ovn_northd.dl | 40 ++++++++++++++++++++-------------------- 6 files changed, 40 insertions(+), 39 deletions(-) diff --git a/northd/helpers.dl b/northd/helpers.dl index 820e37bb3072..757532e46c0e 100644 --- a/northd/helpers.dl +++ b/northd/helpers.dl @@ -23,7 +23,7 @@ output relation Warning[string] /* Switch-to-router logical port connections */ relation SwitchRouterPeer(lsp: uuid, lsp_name: string, lrp: uuid) SwitchRouterPeer(lsp, lsp_name, lrp) :- - nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = "router", .options = options), + &nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = "router", .options = options), Some{var router_port} = options.get("router-port"), &nb::Logical_Router_Port(.name = router_port, ._uuid = lrp). diff --git a/northd/lrouter.dl b/northd/lrouter.dl index 81e4a03e8a91..38a19e7ea324 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -92,7 +92,7 @@ FirstHopLogicalRouter(lrouter, lswitch) :- relation LogicalSwitchRouterPort(lsp: uuid, lsp_router_port: string, ls: uuid) LogicalSwitchRouterPort(lsp, lsp_router_port, ls) :- LogicalSwitchPort(lsp, ls), - nb::Logical_Switch_Port(._uuid = lsp, .__type = "router", .options = options), + &nb::Logical_Switch_Port(._uuid = lsp, .__type = "router", .options = options), Some{var lsp_router_port} = options.get("router-port"). /* diff --git a/northd/lswitch.dl b/northd/lswitch.dl index 7a49ac17dbab..419117f743b3 100644 --- a/northd/lswitch.dl +++ b/northd/lswitch.dl @@ -22,7 +22,7 @@ import helpers import ipam import vec -function is_enabled(lsp: nb::Logical_Switch_Port): bool { is_enabled(lsp.enabled) } +function is_enabled(lsp: Intern): bool { is_enabled(lsp.enabled) } function is_enabled(sp: SwitchPort): bool { sp.lsp.is_enabled() } function is_enabled(sp: Intern): bool { sp.lsp.is_enabled() } @@ -33,7 +33,7 @@ SwitchRouterPeerRef(lsp, Some{rport}) :- rport in &RouterPort(.lrp = &nb::Logical_Router_Port{._uuid = lrp}). SwitchRouterPeerRef(lsp, None) :- - nb::Logical_Switch_Port(._uuid = lsp), + &nb::Logical_Switch_Port(._uuid = lsp), not SwitchRouterPeer(lsp, _, _). /* LogicalSwitchPortCandidate. @@ -50,7 +50,7 @@ Warning[message] :- LogicalSwitchPortCandidate(lsp_uuid, ls_uuid), var lss = ls_uuid.group_by(lsp_uuid).to_set(), lss.size() > 1, - lsp in nb::Logical_Switch_Port(._uuid = lsp_uuid), + lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid), var message = "Bad configuration: logical switch port ${lsp.name} belongs " "to more than one logical switch". @@ -66,7 +66,7 @@ LogicalSwitchPort(lsp_uuid, ls_uuid) :- relation LogicalSwitchPortWithUnknownAddress(ls: uuid, lsp: uuid) LogicalSwitchPortWithUnknownAddress(ls_uuid, lsp_uuid) :- LogicalSwitchPort(lsp_uuid, ls_uuid), - lsp in nb::Logical_Switch_Port(._uuid = lsp_uuid), + lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid), lsp.is_enabled() and lsp.addresses.contains("unknown"). relation LogicalSwitchHasUnknownPorts(ls: uuid, has_unknown: bool) @@ -81,7 +81,7 @@ relation PortStaticAddresses(lsport: uuid, ip4addrs: Set, ip6addrs: Set< PortStaticAddresses(.lsport = port_uuid, .ip4addrs = ip4_addrs.union(), .ip6addrs = ip6_addrs.union()) :- - nb::Logical_Switch_Port(._uuid = port_uuid, .addresses = addresses), + &nb::Logical_Switch_Port(._uuid = port_uuid, .addresses = addresses), var address = FlatMap(if (addresses.is_empty()) { set_singleton("") } else { addresses }), (var ip4addrs, var ip6addrs) = if (not is_dynamic_lsp_address(address)) { split_addresses(address) @@ -133,7 +133,7 @@ relation LogicalSwitchLocalnetPort0(ls_uuid: uuid, lsp: (uuid, string)) LogicalSwitchLocalnetPort0(ls_uuid, (lsp_uuid, lsp.name)) :- ls in nb::Logical_Switch(._uuid = ls_uuid), var lsp_uuid = FlatMap(ls.ports), - lsp in nb::Logical_Switch_Port(._uuid = lsp_uuid), + lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid), lsp.__type == "localnet". relation LogicalSwitchLocalnetPorts(ls_uuid: uuid, localnet_ports: Vec<(uuid, string)>) @@ -173,7 +173,7 @@ relation LogicalSwitchHasNonRouterPort0(ls: uuid) LogicalSwitchHasNonRouterPort0(ls_uuid) :- ls in nb::Logical_Switch(._uuid = ls_uuid), var lsp_uuid = FlatMap(ls.ports), - lsp in nb::Logical_Switch_Port(._uuid = lsp_uuid), + lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid), lsp.__type != "router". relation LogicalSwitchHasNonRouterPort(ls: uuid, has_non_router_port: bool) @@ -512,9 +512,9 @@ relation &SwitchACL(sw: Intern, function oVN_FEATURE_PORT_UP_NOTIF(): string { "port-up-notif" } relation SwitchPortUp0(lsp: uuid) SwitchPortUp0(lsp) :- - nb::Logical_Switch_Port(._uuid = lsp, .__type = "router"). + &nb::Logical_Switch_Port(._uuid = lsp, .__type = "router"). SwitchPortUp0(lsp) :- - nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = __type), + &nb::Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = __type), sb::Port_Binding(.logical_port = lsp_name, .up = up, .chassis = Some{chassis_uuid}), sb::Chassis(._uuid = chassis_uuid, .other_config = other_config), if (other_config.get_bool_def(oVN_FEATURE_PORT_UP_NOTIF(), false)) { @@ -525,11 +525,11 @@ SwitchPortUp0(lsp) :- relation SwitchPortUp(lsp: uuid, up: bool) SwitchPortUp(lsp, true) :- SwitchPortUp0(lsp). -SwitchPortUp(lsp, false) :- nb::Logical_Switch_Port(._uuid = lsp), not SwitchPortUp0(lsp). +SwitchPortUp(lsp, false) :- &nb::Logical_Switch_Port(._uuid = lsp), not SwitchPortUp0(lsp). relation SwitchPortHAChassisGroup0(lsp_uuid: uuid, hac_group_uuid: uuid) SwitchPortHAChassisGroup0(lsp_uuid, ha_chassis_group_uuid(ls_uuid)) :- - lsp in nb::Logical_Switch_Port(._uuid = lsp_uuid), + lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid), lsp.__type == "external", Some{var hac_group_uuid} = lsp.ha_chassis_group, ha_chassis_group in nb::HA_Chassis_Group(._uuid = hac_group_uuid), @@ -542,7 +542,7 @@ relation SwitchPortHAChassisGroup(lsp_uuid: uuid, hac_group_uuid: Option) SwitchPortHAChassisGroup(lsp_uuid, Some{hac_group_uuid}) :- SwitchPortHAChassisGroup0(lsp_uuid, hac_group_uuid). SwitchPortHAChassisGroup(lsp_uuid, None) :- - lsp in nb::Logical_Switch_Port(._uuid = lsp_uuid), + lsp in &nb::Logical_Switch_Port(._uuid = lsp_uuid), not SwitchPortHAChassisGroup0(lsp_uuid, _). /* SwitchPort relation collects all attributes of a logical switch port @@ -558,7 +558,7 @@ SwitchPortHAChassisGroup(lsp_uuid, None) :- * - 'hac_group_uuid' - uuid of sb::HA_Chassis_Group, only for "external" ports */ typedef SwitchPort = SwitchPort { - lsp: nb::Logical_Switch_Port, + lsp: Intern, json_name: string, sw: Intern, peer: Option>, @@ -602,7 +602,7 @@ SwitchPort[SwitchPort{ .mcast_cfg = mcast_cfg, .hac_group_uuid = hac_group_uuid }.intern()] :- - nb::Logical_Switch_Port[lsp], + lsp in &nb::Logical_Switch_Port(), LogicalSwitchPort(lsp._uuid, lswitch_uuid), sw in &Switch(._uuid = lswitch_uuid, .other_config = other_config, diff --git a/northd/multicast.dl b/northd/multicast.dl index bd9bc9b46f61..dfd58f4770bd 100644 --- a/northd/multicast.dl +++ b/northd/multicast.dl @@ -96,7 +96,7 @@ typedef McastPortCfg = McastPortCfg { relation McastPortCfg[Intern] McastPortCfg[McastPortCfg{lsp_uuid, false, flood, flood_reports}.intern()] :- - nb::Logical_Switch_Port(._uuid = lsp_uuid, .options = options), + &nb::Logical_Switch_Port(._uuid = lsp_uuid, .options = options), var flood = options.get_bool_def("mcast_flood", false), var flood_reports = options.get_bool_def("mcast_flood_reports", false). @@ -195,7 +195,7 @@ IgmpSwitchGroupPort(address, switch, lsp_uuid) :- var pb_port_uuid = FlatMap(pb_ports), sb::Port_Binding(._uuid = pb_port_uuid, .logical_port = lsp_name), &SwitchPort( - .lsp = nb::Logical_Switch_Port{._uuid = lsp_uuid, .name = lsp_name}, + .lsp = &nb::Logical_Switch_Port{._uuid = lsp_uuid, .name = lsp_name}, .sw = switch). IgmpSwitchGroupPort(address, switch, localnet_port.0) :- IgmpSwitchGroupPort(address, switch, _), @@ -235,7 +235,7 @@ IgmpRouterGroupPort(address, rtr_port.router, rtr_port.lrp._uuid) :- None -> true }, var flood_port = FlatMap(sw_flood_ports), - &SwitchPort(.lsp = nb::Logical_Switch_Port{._uuid = flood_port}, + &SwitchPort(.lsp = &nb::Logical_Switch_Port{._uuid = flood_port}, .peer = Some{rtr_port}). /* Aggregated IGMP group for routers: merges all IgmpRouterGroupPort for diff --git a/northd/ovn-nb.dlopts b/northd/ovn-nb.dlopts index c1ceb4f1496a..402a44636ab9 100644 --- a/northd/ovn-nb.dlopts +++ b/northd/ovn-nb.dlopts @@ -22,3 +22,4 @@ --intern-table NAT --intern-table Address_Set --intern-table Logical_Router_Port +--intern-table Logical_Switch_Port diff --git a/northd/ovn_northd.dl b/northd/ovn_northd.dl index 045a054105bc..cfa348d90efc 100644 --- a/northd/ovn_northd.dl +++ b/northd/ovn_northd.dl @@ -493,7 +493,7 @@ RefChassis(lr_uuid, chassis_uuid) :- ReachableLogicalRouter(lr_uuid, lr2_uuid), FirstHopLogicalRouter(lr2_uuid, ls_uuid), LogicalSwitchPort(lsp_uuid, ls_uuid), - nb::Logical_Switch_Port(._uuid = lsp_uuid, .name = lsp_name), + &nb::Logical_Switch_Port(._uuid = lsp_uuid, .name = lsp_name), sb::Port_Binding(.logical_port = lsp_name, .chassis = chassis_uuids), Some{var chassis_uuid} = chassis_uuids. relation RefChassisSet0(lr_uuid: uuid, chassis_uuids: Set) @@ -717,7 +717,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, pg_ip4addrs.union()) :- // avoid name collisions with user-defined Address_Sets not &nb::Address_Set(.name = as_name), PortStaticAddresses(.lsport = port_uuid, .ip4addrs = stat), - SwitchPortNewDynamicAddress(&SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = port_uuid}}, + SwitchPortNewDynamicAddress(&SwitchPort{.lsp = &nb::Logical_Switch_Port{._uuid = port_uuid}}, dyn_addr), var dynamic = match (dyn_addr) { None -> set_empty(), @@ -742,7 +742,7 @@ sb::Out_Address_Set(hash128(as_name), as_name, pg_ip6addrs.union()) :- // avoid name collisions with user-defined Address_Sets not &nb::Address_Set(.name = as_name), PortStaticAddresses(.lsport = port_uuid, .ip6addrs = stat), - SwitchPortNewDynamicAddress(&SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = port_uuid}}, + SwitchPortNewDynamicAddress(&SwitchPort{.lsp = &nb::Logical_Switch_Port{._uuid = port_uuid}}, dyn_addr), var dynamic = match (dyn_addr) { None -> set_empty(), @@ -781,8 +781,8 @@ PortGroupPort(pg_uuid, pg_name, port) :- sb::Out_Port_Group(._uuid = hash128(sb_name), .name = sb_name, .ports = port_names) :- PortGroupPort(.pg_uuid = _uuid, .pg_name = nb_name, .port = port_uuid), - &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{._uuid = port_uuid, - .name = port_name}, + &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{._uuid = port_uuid, + .name = port_name}, .sw = &Switch{._uuid = ls_uuid}), TunKeyAllocation(.datapath = ls_uuid, .tunkey = tunkey), var sb_name = "${tunkey}_${nb_name}", @@ -1839,7 +1839,7 @@ for (&Switch(._uuid =ls_uuid)) { * send all IP packets through the conntrack action, which handles * defragmentation, in order to match L4 headers. */ -for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "router"}, +for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = "router"}, .json_name = lsp_name, .sw = &Switch{._uuid = ls_uuid, .has_stateful_acl = true})) { /* Can't use ct() for router ports. Consider the @@ -1868,7 +1868,7 @@ for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "router"}, .external_ids = stage_hint(lsp._uuid)) } -for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "localnet"}, +for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = "localnet"}, .json_name = lsp_name, .sw = &Switch{._uuid = ls_uuid, .has_stateful_acl = true})) { Flow(.logical_datapath = ls_uuid, @@ -2760,7 +2760,7 @@ for (&Switch(._uuid = ls_uuid, .load_balancer = load_balancer, .has_lb_vip = has .external_ids = map_empty()); if (not load_balancer.is_empty()) { - for (&SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "router"}, + for (&SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = "router"}, .json_name = lsp_name, .sw = &Switch{._uuid = ls_uuid})) { Flow(.logical_datapath = ls_uuid, @@ -3259,7 +3259,7 @@ for (&SwitchPort(.lsp = lsp, .sw = sw, .json_name = json_name) .external_ids = stage_hint(lsp._uuid)) } -function lsp_is_up(lsp: nb::Logical_Switch_Port): bool = { +function lsp_is_up(lsp: Intern): bool = { lsp.up == Some{true} } @@ -3280,12 +3280,12 @@ function lsp_is_up(lsp: nb::Logical_Switch_Port): bool = { "(arp.op == 2 && arp.spa == ${virtual_ip}))", .actions = "bind_vport(${sp.json_name}, inport); next;", .external_ids = stage_hint(lsp._uuid)) :- - sp in &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "virtual"}), + sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = "virtual"}), Some{var virtual_ip} = lsp.options.get("virtual-ip"), Some{var virtual_parents} = lsp.options.get("virtual-parents"), Some{var ip} = ip_parse(virtual_ip), var vparent = FlatMap(string_split(virtual_parents, ",")), - vp in &SwitchPort(.lsp = nb::Logical_Switch_Port{.name = vparent}), + vp in &SwitchPort(.lsp = &nb::Logical_Switch_Port{.name = vparent}), vp.sw == sp.sw. /* @@ -3414,7 +3414,7 @@ Flow(.logical_datapath = sp.sw._uuid, var lbvipbackend = FlatMap(lbvip.backends), Some{var svc_monitor} = lbvipbackend.svc_monitor, sp in &SwitchPort( - .lsp = nb::Logical_Switch_Port{.name = svc_monitor.port_name}), + .lsp = &nb::Logical_Switch_Port{.name = svc_monitor.port_name}), var svc_mon_src_ip = svc_monitor.src_ip, SvcMonitorMac(svc_monitor_mac). @@ -3606,7 +3606,7 @@ for (lsp in &SwitchPort Some{var dhcpv4_options_uuid} = lsp.lsp.dhcpv4_options in { for (dhcpv4_options in &nb::DHCP_Options(._uuid = dhcpv4_options_uuid)) { - for (SwitchPortIPv4Address(.port = &SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = lsp.lsp._uuid}}, .ea = ea, .addr = addr)) { + for (SwitchPortIPv4Address(.port = &SwitchPort{.lsp = &nb::Logical_Switch_Port{._uuid = lsp.lsp._uuid}}, .ea = ea, .addr = addr)) { Some{(var options_action, var response_action, var ipv4_addr_match)} = build_dhcpv4_action(json_key, dhcpv4_options, addr.addr) in { @@ -3663,7 +3663,7 @@ for (lsp in &SwitchPort Some{var dhcpv6_options_uuid} = lsp.lsp.dhcpv6_options in { for (dhcpv6_options in &nb::DHCP_Options(._uuid = dhcpv6_options_uuid)) { - for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = nb::Logical_Switch_Port{._uuid = lsp.lsp._uuid}}, .ea = ea, .addr = addr)) { + for (SwitchPortIPv6Address(.port = &SwitchPort{.lsp = &nb::Logical_Switch_Port{._uuid = lsp.lsp._uuid}}, .ea = ea, .addr = addr)) { Some{(var options_action, var response_action)} = build_dhcpv6_action(json_key, dhcpv6_options, addr.addr) in { @@ -4322,7 +4322,7 @@ Flow(.logical_datapath = ls_uuid, .actions = "put_fdb(inport, eth.src); next;", .external_ids = stage_hint(lsp_uuid)) :- LogicalSwitchPortWithUnknownAddress(ls_uuid, lsp_uuid), - sp in &SwitchPort(.lsp = nb::Logical_Switch_Port{._uuid = lsp_uuid, .__type = ""}, + sp in &SwitchPort(.lsp = &nb::Logical_Switch_Port{._uuid = lsp_uuid, .__type = ""}, .ps_addresses = vec_empty()). Flow(.logical_datapath = ls_uuid, @@ -6988,7 +6988,7 @@ Flow(.logical_datapath = peer.router._uuid, "${rEG_NEXT_HOP()} == ${virtual_ip}", .actions = "eth.dst = 00:00:00:00:00:00; next;", .external_ids = stage_hint(sp.lsp._uuid)) :- - sp in &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "virtual"}), + sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = "virtual"}), Some{var virtual_ip_s} = lsp.options.get("virtual-ip"), Some{var virtual_parents} = lsp.options.get("virtual-parents"), Some{var virtual_ip} = ip_parse(virtual_ip_s), @@ -7003,14 +7003,14 @@ Flow(.logical_datapath = peer.router._uuid, "${rEG_NEXT_HOP()} == ${virtual_ip}", .actions = "eth.dst = ${address.ea}; next;", .external_ids = stage_hint(sp.lsp._uuid)) :- - sp in &SwitchPort(.lsp = lsp@nb::Logical_Switch_Port{.__type = "virtual"}), + sp in &SwitchPort(.lsp = lsp@&nb::Logical_Switch_Port{.__type = "virtual"}), Some{var virtual_ip_s} = lsp.options.get("virtual-ip"), Some{var virtual_parents} = lsp.options.get("virtual-parents"), Some{var virtual_ip} = ip_parse(virtual_ip_s), pb in sb::Port_Binding(.logical_port = sp.lsp.name), not (is_empty_set_or_string(pb.virtual_parent) or pb.chassis == None), Some{var virtual_parent} = pb.virtual_parent, - vp in &SwitchPort(.lsp = nb::Logical_Switch_Port{.name = virtual_parent}), + vp in &SwitchPort(.lsp = &nb::Logical_Switch_Port{.name = virtual_parent}), var address = FlatMap(vp.static_addresses), sp2 in &SwitchPort(.sw = sp.sw, .peer = Some{peer}), Some{_} = find_lrp_member_ip(peer.networks, IPv4{virtual_ip}). @@ -7670,7 +7670,7 @@ SwitchPortReservedTags(parent_name, tags) :- var tags = tag.group_by(parent_name).to_set(). SwitchPortReservedTags(parent_name, set_empty()) :- - nb::Logical_Switch_Port(.name = parent_name), + &nb::Logical_Switch_Port(.name = parent_name), not SwitchPortReservedTag(.parent_name = parent_name). /* Allocate tags for ports that require dynamically allocated tags and do not @@ -7732,7 +7732,7 @@ sb::Out_IP_Multicast(._uuid = cfg.datapath, relation PortExists(name: string) -PortExists(name) :- nb::Logical_Switch_Port(.name = name). +PortExists(name) :- &nb::Logical_Switch_Port(.name = name). PortExists(name) :- &nb::Logical_Router_Port(.name = name). sb::Out_Load_Balancer(._uuid = lb._uuid, From patchwork Sat Mar 27 00:31:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459086 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp1.osuosl.org (smtp1.osuosl.org [140.211.166.138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fwZ1DjHz9sCD for ; Sat, 27 Mar 2021 11:34:06 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 035BB8291C; Sat, 27 Mar 2021 00:34:03 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ILa94XpfLulm; Sat, 27 Mar 2021 00:34:00 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTP id ECD0484E2B; Sat, 27 Mar 2021 00:33:44 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id BE641C000B; Sat, 27 Mar 2021 00:33:44 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [140.211.166.136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 06D19C000A for ; Sat, 27 Mar 2021 00:33:44 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 84C8F60DC0 for ; Sat, 27 Mar 2021 00:32:39 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ZpLEPqBT0SZc for ; Sat, 27 Mar 2021 00:32:36 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp3.osuosl.org (Postfix) with ESMTPS id 653C260E07 for ; Sat, 27 Mar 2021 00:32:30 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 9F13CFF802; Sat, 27 Mar 2021 00:32:27 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:46 -0700 Message-Id: <20210327003147.2955790-21-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Leonid Ryzhyk , Ben Pfaff Subject: [ovs-dev] [PATCH ovn 20/21] ovn-northd-ddlog: Remove Router.static_routes. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: Leonid Ryzhyk This is another instance of a performance bug when a change to a router object forces a cascade of changes to relations that reference the object. This time around the problem was caused by the `Router.static_routes` field, which is copied from `nb::Logical_Router`. Luckily, this field was only used in one rule and was easy to remove. Here is how we diagnosed the issue (this may be useful for posterity): - We started with a benchmark that executed several hundreds of similar transactions (in this case, these transactions were adding new router ports). We recorded execution of the benchmark in a DDlog command file (replay.txt) and added `timestamp;` commands after each transaction in the file. - Run `make NORTHD_CLI=1` to generate the ovn_northd_cli executable and use it to execute the command file: ``` ./ovn_northd_ddlog/target/release/ovn_northd_cli -w 1 < replay.txt > replay.dump ``` - Extract only the timestamps from replay.dump and plot differences between successive timestamps (i.e., individual transaction times). I use gnumeric. It would be nice to have some automation for this in the future. We observe that one of the transactions in the benchmark loop slows down linearly as the size of the network topology grows: https://gist.github.com/ryzhyk/16a5607b280ed9cd09b176d6816cb4f0 Clearly some of the rules in the program are getting more expensive as the number of ports goes up. Another interesting observation is that the size of the delta output at each iteration of the benchmark remains constant (the delta mostly consists of new network flows). This suggests that whatever extra work DDlog is doing at each iteration might be redundant. - To identify where the wasted work happens, we re-compile the program passing the `--output-internal-relations` flag to DDlog, which tells it to dump changes to all intermediate relations, not just output relation. We replay the trace again. We locate the expensive transaction in the log and compare its output from one of the first iterations vs one from the end of the log. We now see a whole bunch of intermediate relations that only had a few modified records in the first transaction versus hundreds in the second one. We further observe that all of these changes simply update the `static_routes` field (as explained above). - After removing the field, we observe that changes to intermediate relations no longer grow with the topology, and transaction timing increases much more slowly: https://gist.github.com/ryzhyk/d02784b9088d82f8549ea1b2ebdf095e Signed-off-by: Leonid Ryzhyk Signed-off-by: Ben Pfaff --- northd/lrouter.dl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/northd/lrouter.dl b/northd/lrouter.dl index 38a19e7ea324..7ed5358c9431 100644 --- a/northd/lrouter.dl +++ b/northd/lrouter.dl @@ -434,7 +434,6 @@ typedef Router = Router { /* Fields copied from nb::Logical_Router. */ _uuid: uuid, name: string, - static_routes: Set, policies: Set, enabled: Option, nat: Set, @@ -459,7 +458,6 @@ relation Router[Intern] Router[Router{ ._uuid = lr._uuid, .name = lr.name, - .static_routes = lr.static_routes, .policies = lr.policies, .enabled = lr.enabled, .nat = lr.nat, @@ -730,7 +728,8 @@ RouterStaticRoute_(.router = router, .nexthop = route.nexthop, .output_port = route.output_port, .ecmp_symmetric_reply = route.ecmp_symmetric_reply) :- - router in &Router(.static_routes = routes), + router in &Router(), + nb::Logical_Router(._uuid = router._uuid, .static_routes = routes), var route_id = FlatMap(routes), route in &StaticRoute(.lrsr = nb::Logical_Router_Static_Route{._uuid = route_id}). From patchwork Sat Mar 27 00:31:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Pfaff X-Patchwork-Id: 1459088 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4F6fwk2Pzqz9sCD for ; Sat, 27 Mar 2021 11:34:14 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 7555C418BC; Sat, 27 Mar 2021 00:34:12 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id f9oJGytevaQE; Sat, 27 Mar 2021 00:34:09 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp4.osuosl.org (Postfix) with ESMTP id BB15240149; Sat, 27 Mar 2021 00:33:48 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id AB7CCC000D; Sat, 27 Mar 2021 00:33:48 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) by lists.linuxfoundation.org (Postfix) with ESMTP id 23026C000B for ; Sat, 27 Mar 2021 00:33:47 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id C3A8240694 for ; Sat, 27 Mar 2021 00:32:43 +0000 (UTC) X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id XiX8LB0KKtxQ for ; Sat, 27 Mar 2021 00:32:42 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 Received: from relay9-d.mail.gandi.net (relay9-d.mail.gandi.net [217.70.183.199]) by smtp2.osuosl.org (Postfix) with ESMTPS id E998A40656 for ; Sat, 27 Mar 2021 00:32:31 +0000 (UTC) X-Originating-IP: 75.54.222.30 Received: from sigfpe.attlocal.net (75-54-222-30.lightspeed.rdcyca.sbcglobal.net [75.54.222.30]) (Authenticated sender: blp@ovn.org) by relay9-d.mail.gandi.net (Postfix) with ESMTPSA id 45F21FF805; Sat, 27 Mar 2021 00:32:28 +0000 (UTC) From: Ben Pfaff To: dev@openvswitch.org Date: Fri, 26 Mar 2021 17:31:47 -0700 Message-Id: <20210327003147.2955790-22-blp@ovn.org> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210327003147.2955790-1-blp@ovn.org> References: <20210327003147.2955790-1-blp@ovn.org> MIME-Version: 1.0 Cc: Ben Pfaff Subject: [ovs-dev] [PATCH ovn 21/21] tutorial: Add benchmarking test script to run within sandbox. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" This is originally from Numan Siddique. I have adapted it a bit to run faster by using the ovn-nbctl and ovn-sbctl daemons and combining multiple calls into just one. I'm uncertain whether to actually commit this; I need a sign-off from Numan to do so. Signed-off-by: Ben Pfaff CC: Numan Siddique --- tutorial/automake.mk | 3 +- tutorial/northd_ddlog_test.sh | 81 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100755 tutorial/northd_ddlog_test.sh diff --git a/tutorial/automake.mk b/tutorial/automake.mk index 13b3bee055c9..f2571c2cfd98 100644 --- a/tutorial/automake.mk +++ b/tutorial/automake.mk @@ -6,7 +6,8 @@ EXTRA_DIST += \ tutorial/t-stage2 \ tutorial/t-stage3 \ tutorial/t-stage4 \ - tutorial/ovn-setup.sh + tutorial/ovn-setup.sh \ + tutorial/northd_ddlog_test.sh sandbox: all cd $(srcdir)/tutorial && MAKE=$(MAKE) HAVE_OPENSSL=$(HAVE_OPENSSL) \ ./ovs-sandbox -b $(abs_builddir) --ovs-src $(ovs_srcdir) --ovs-build $(ovs_builddir) $(SANDBOXFLAGS) diff --git a/tutorial/northd_ddlog_test.sh b/tutorial/northd_ddlog_test.sh new file mode 100755 index 000000000000..57e45d96228f --- /dev/null +++ b/tutorial/northd_ddlog_test.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +ddlog_running () { + test -e sandbox/ovn-north-ddlog.pid +} + +rm -f sandbox/profile-[0-9]*.txt +if ddlog_running; then + ovs-appctl -t ovn-northd-ddlog enable-cpu-profiling +fi + +export OVN_NB_DAEMON=$(ovn-nbctl --pidfile --detach) +export OVN_SB_DAEMON=$(ovn-sbctl --pidfile --detach) +trap 'kill $(cat $OVN_RUNDIR/ovn-nbctl.pid) $(cat $OVN_RUNDIR/ovn-sbctl.pid)' 0 + +ovn-nbctl set NB_Global . options:northd_probe_interval=180000 + +ovn-nbctl pg-add portGroupDefDeny +ovn-nbctl pg-add portGroupMultiDefDeny +ovn-nbctl lr-add cluster_router + +step () { + lswitch_name=lswitch_17.${i}.0.0/16 + ext_switch=ext_ls_2.${i}.0.0/16 + ext_lrouter=ext_lr_2.${i}.0.0/16 + j=2 + port_name=lp_17.${i}.0.${j} + port_ip=17.${i}.0.${j} + np=networkPolicy-$i-$j + ns=nameSpace-$i-$j + mg=mcastPortGroup_$ns + ovn-sbctl chassis-add ch$i geneve 128.0.0.$i + ovn-nbctl --wait=sb \ + ls-add ${lswitch_name} -- \ + lrp-add cluster_router lr-$lswitch_name 00:00:00:00:ff:$i 17.${i}.0.254/16 -- \ + lsp-add $lswitch_name $lswitch_name-lr -- \ + lsp-set-type $lswitch_name-lr router -- \ + lsp-set-addresses $lswitch_name-lr router -- \ + lsp-set-options $lswitch_name-lr router-port=lr-$lswitch_name -- \ + ls-add $ext_switch -- \ + lr-add $ext_lrouter -- \ + lrp-add $ext_lrouter extlr-$lswitch_name 00:00:00:10:af:$i 2.${i}.0.254/16 -- \ + lsp-add $ext_switch $ext_switch-lr_2.$i -- \ + lsp-set-type $ext_switch-lr_2.$i router -- \ + lsp-set-addresses $ext_switch-lr_2.$i router -- \ + lsp-set-options $ext_switch-lr_2.$i router-port=extlr-$lswitch_name -- \ + lr-nat-add $ext_lrouter snat 2.${i}.0.100 17.${i}.0.0/16 -- \ + lr-route-add $ext_lrouter 17.${i}.1.0/16 20.0.0.2 -- \ + --policy="src-ip" lr-route-add $ext_lrouter 192.168.2.0/24 20.0.0.3 -- \ + --policy="src-ip" lr-route-add cluster_router 17.${i}.1.0/16 20.0.0.4 -- \ + set logical_router $ext_lrouter options:chassis=ch$i -- \ + lsp-add ${lswitch_name} ${port_name} -- \ + lsp-set-addresses ${port_name} "dynamic ${port_ip}" -- \ + --id=@lsp get logical_switch_port ${port_name} -- \ + add port_group portGroupDefDeny ports @lsp -- \ + add port_group portGroupMultiDefDeny ports @lsp -- \ + pg-add $np $port_name -- \ + create Address_Set name=${np}_ingress_as addresses=$port_ip -- \ + create Address_Set name=${np}_egress_as addresses=$port_ip -- \ + acl-add $np from-lport 1010 "inport == @$np && ip4.src == ${np}_ingress_as" allow -- \ + acl-add $np from-lport 1009 "inport == @$np && ip4" allow-related -- \ + acl-add $np to-lport 1010 "outport == @$np && ip4.dst == ${np}_egress_as" allow -- \ + acl-add $np to-lport 1009 "outport == @$np && ip4" allow -- \ + create Address_Set name=$ns addresses=$port_ip -- \ + pg-add $mg $port_name -- \ + acl-add $mg from-lport 1012 "inport == @${mg} && ip4.mcast" allow -- \ + acl-add $mg to-lport 1012 "outport == @${mg} && ip4.mcast" allow >/dev/null + ovn-sbctl lsp-bind $port_name ch$i + + if ddlog_running; then + ovs-appctl -t ovn-northd-ddlog profile > sandbox/profile-$i.txt + fi +} + +rm -f timings +i=1 +while [ $i -lt 255 ] +do + printf "step $i: "; TIMEFORMAT=%R; time step + i=$((i+1)) +done