Hi Dumitru, Mark, Numan,

Could you please consider this patch for OVN 26.03  release ?
Since there is no enough time to review entire Active/Active  patch for 26.03 , 
we thought it is better to commit this schema changes for 26.03.
The plan is to modify the code to store nf-id in CT label instead of nfg-id in 
Active/Active patch. This is required to avoid switching existing connections 
going to healthy NFs when no.of healthy NFs count in an NFG changes.
Please let us know if there any concerns or other suggestions.

Thanks,
Naveen

From: Aditya Mehakare <[email protected]>
Date: Tuesday, 20 January 2026 at 8:16 PM
To: [email protected] <[email protected]>
Cc: Aditya Mehakare <[email protected]>, Naveen Yerramneni 
<[email protected]>
Subject: [PATCH ovn] ovn-nb, ovn-nbctl: Add ID column to Network_Function table.
This commit introduces a new 'id' column to the Network_Function table
in the OVN Northbound database schema. The ID is a mandatory integer
field (range 1-255) with a unique index constraint.

This change is required to support network function active-active mode
in future releases. The ID will be used to uniquely identify network
functions in scenarios where multiple instances need to be managed
simultaneously.

Since this is a schema change that is not backward compatible, it is
being introduced in the current release to ensure smoother upgrades
when active-active mode support is added in subsequent releases.

Schema changes:
- Added 'id' column to Network_Function table (integer, 1-255)
- Added unique index on 'id' column alongside existing 'name' index

Changes to ovn-nbctl:
- Updated nf-add command to require ID parameter:
  nf-add NETWORK-FUNCTION ID PORT-IN PORT-OUT
- Modified nf-list to display the ID field
- Updated related documentation, and tests

Signed-off-by: Aditya Mehakare <[email protected]>
Acked-by: Naveen Yerramneni <[email protected]>
---
 ovn-nb.ovsschema          | 10 +++++---
 ovn-nb.xml                |  5 ++++
 tests/ovn-nbctl.at        | 48 +++++++++++++++++++++++++++------------
 tests/ovn-northd.at       |  8 +++----
 tests/ovn.at              |  6 ++---
 tests/system-ovn.at       |  4 ++--
 utilities/ovn-nbctl.8.xml | 19 ++++++++--------
 utilities/ovn-nbctl.c     | 25 +++++++++++++++-----
 8 files changed, 84 insertions(+), 41 deletions(-)

diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
index 8c2c1d861..2c60d000c 100644
--- a/ovn-nb.ovsschema
+++ b/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
 {
     "name": "OVN_Northbound",
-    "version": "7.15.0",
-    "cksum": "4060410729 43708",
+    "version": "7.16.0",
+    "cksum": "3182666148 43912",
     "tables": {
         "NB_Global": {
             "columns": {
@@ -213,10 +213,14 @@
                             "refTable": "Network_Function_Health_Check",
                             "refType": "strong"},
                     "min": 0, "max": 1}},
+                "id": {
+                     "type": {"key": {"type": "integer",
+                                      "minInteger": 1,
+                                      "maxInteger": 255}}},
                 "external_ids": {
                     "type": {"key": "string", "value": "string",
                              "min": 0, "max": "unlimited"}}},
-            "indexes": [["name"]],
+            "indexes": [["name"], ["id"]],
             "isRoot": true},
         "Network_Function_Group": {
             "columns": {
diff --git a/ovn-nb.xml b/ovn-nb.xml
index e74c0d010..4f71fe0e7 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -6382,6 +6382,11 @@ or
       Name of the <ref table="Network_Function"/>. Name should be unique.
     </column>

+    <column name="id">
+      A unique integer between 1 and 255 must be assigned to each
+      <code>Network_Function</code>.
+    </column>
+
     <column name="inport">
       <ref table="Logical_Switch_Port"/>  where request traffic for from-lport
       ACL and response traffic for to-lport ACL is redirected.
diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
index dccf30758..f4cb89b82 100644
--- a/tests/ovn-nbctl.at
+++ b/tests/ovn-nbctl.at
@@ -3245,13 +3245,13 @@ AT_CHECK([check ovn-nbctl set logical_switch_port 
svc-port1 \
     options:is-nf=true options:nf-linked-port=svc-port0])

 # Create network-function.
-AT_CHECK([ovn-nbctl nf-add nf0 svc-port0 svc-port1])
-AT_CHECK([ovn-nbctl nf-add nf0 svc-port0 svc-port1], [1], [],
+AT_CHECK([ovn-nbctl nf-add nf0 1 svc-port0 svc-port1])
+AT_CHECK([ovn-nbctl nf-add nf0 1 svc-port0 svc-port1], [1], [],
   [ovn-nbctl: nf0: same name network-function already exists
 ])
-AT_CHECK([ovn-nbctl --may-exist nf-add nf0 svc-port0 svc-port1])
+AT_CHECK([ovn-nbctl --may-exist nf-add nf0 1 svc-port0 svc-port1])
 AT_CHECK([ovn-nbctl nf-list | uuidfilt], [0], [dnl
-<0> (nf0) in:svc-port0 out:svc-port1
+<0> (nf0) id:1 in:svc-port0 out:svc-port1
 ])

 # Test --may-exist overwrite behavior: update existing network function with 
new ports
@@ -3263,25 +3263,25 @@ AT_CHECK([check ovn-nbctl set logical_switch_port 
svc-port4 \
 AT_CHECK([check ovn-nbctl set logical_switch_port svc-port5 \
     options:receive_multicast=false options:lsp_learn_fdb=false \
     options:is-nf=true options:nf-linked-port=svc-port4])
-AT_CHECK([ovn-nbctl --may-exist nf-add nf0 svc-port4 svc-port5])
+AT_CHECK([ovn-nbctl --may-exist nf-add nf0 1 svc-port4 svc-port5])
 AT_CHECK([ovn-nbctl nf-list | uuidfilt], [0], [dnl
-<0> (nf0) in:svc-port4 out:svc-port5
+<0> (nf0) id:1 in:svc-port4 out:svc-port5
 ])

 # Create two more network-functions, one with same inport and outport.
 AT_CHECK([check ovn-nbctl lsp-add ls0 svc-port2])
 AT_CHECK([check ovn-nbctl lsp-add ls0 svc-port3])
-AT_CHECK([ovn-nbctl nf-add nf1 svc-port2 svc-port3])
+AT_CHECK([ovn-nbctl nf-add nf1 2 svc-port2 svc-port3])
 AT_CHECK([ovn-nbctl nf-list | uuidfilt], [0], [dnl
-<0> (nf0) in:svc-port4 out:svc-port5
-<1> (nf1) in:svc-port2 out:svc-port3
+<0> (nf0) id:1 in:svc-port4 out:svc-port5
+<1> (nf1) id:2 in:svc-port2 out:svc-port3
 ])

-AT_CHECK([ovn-nbctl nf-add nf2 svc-port2 svc-port2])
+AT_CHECK([ovn-nbctl nf-add nf2 3 svc-port2 svc-port2])
 AT_CHECK([ovn-nbctl nf-list | uuidfilt], [0], [dnl
-<0> (nf0) in:svc-port4 out:svc-port5
-<1> (nf1) in:svc-port2 out:svc-port3
-<2> (nf2) in:svc-port2 out:svc-port2
+<0> (nf0) id:1 in:svc-port4 out:svc-port5
+<1> (nf1) id:2 in:svc-port2 out:svc-port3
+<2> (nf2) id:3 in:svc-port2 out:svc-port2
 ])

 # Create a network-function-group.
@@ -3334,10 +3334,30 @@ AT_CHECK([ovn-nbctl nfg-list | uuidfilt], [0], [])
 AT_CHECK([ovn-nbctl nf-del nf1])
 AT_CHECK([ovn-nbctl nf-del nf0])
 AT_CHECK([ovn-nbctl nf-list | uuidfilt], [0], [dnl
-<0> (nf2) in:svc-port2 out:svc-port2
+<0> (nf2) id:3 in:svc-port2 out:svc-port2
 ])
 AT_CHECK([ovn-nbctl nf-del nf2])
 AT_CHECK([ovn-nbctl nf-list | uuidfilt], [0], [])
+
+# Test ID validation and uniqueness
+AT_CHECK([check ovn-nbctl lsp-add ls0 svc-port6])
+AT_CHECK([check ovn-nbctl lsp-add ls0 svc-port7])
+# Test invalid ID (out of range)
+AT_CHECK([ovn-nbctl nf-add nf3 0 svc-port6 svc-port7], [1], [],
+  [ovn-nbctl: network-function id must be between 1 and 255
+])
+AT_CHECK([ovn-nbctl nf-add nf3 256 svc-port6 svc-port7], [1], [],
+  [ovn-nbctl: network-function id must be between 1 and 255
+])
+AT_CHECK([ovn-nbctl nf-add nf3 abc svc-port6 svc-port7], [1], [],
+  [ovn-nbctl: network-function id must be between 1 and 255
+])
+# Test valid ID
+AT_CHECK([ovn-nbctl nf-add nf3 10 svc-port6 svc-port7])
+AT_CHECK([ovn-nbctl nf-list | uuidfilt], [0], [dnl
+<0> (nf3) id:10 in:svc-port6 out:svc-port7
+])
+AT_CHECK([ovn-nbctl nf-del nf3])
 ])

 AT_SETUP([ovn-nbctl - TLS server name indication (SNI) with --ssl-server-name])
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 25655c456..9a1cfdb99 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -18438,7 +18438,7 @@ check ovn-nbctl set logical_switch_port sw0-nf-p1 \
 check ovn-nbctl set logical_switch_port sw0-nf-p2 \
     options:receive_multicast=false options:lsp_learn_mac=false \
     options:is-nf=true options:nf-linked-port=sw0-nf-p1
-check ovn-nbctl nf-add nf0 sw0-nf-p1 sw0-nf-p2
+check ovn-nbctl nf-add nf0 1 sw0-nf-p1 sw0-nf-p2
 check ovn-nbctl nfg-add nfg0 1 inline nf0

 check ovn-nbctl lsp-add sw0 sw0-p1 -- lsp-set-addresses sw0-p1 
"00:00:00:00:00:01 10.0.0.2"
@@ -18551,7 +18551,7 @@ check ovn-nbctl set logical_switch_port sw0-nf-p3 \
 check ovn-nbctl set logical_switch_port sw0-nf-p4 \
     options:receive_multicast=false options:lsp_learn_mac=false \
     options:is-nf=true options:nf-linked-port=sw0-nf-p3
-check ovn-nbctl nf-add nf1 sw0-nf-p3 sw0-nf-p4
+check ovn-nbctl nf-add nf1 2 sw0-nf-p3 sw0-nf-p4
 check ovn-nbctl nfg-add nfg1 2 inline nf1
 check ovn-nbctl acl-add pg0 to-lport 1003 "outport == @pg0 && ip4.src == 
10.0.0.4" allow-related nfg1
 check ovn-sbctl lsp-bind sw0-nf-p3 hv1
@@ -18729,8 +18729,8 @@ check ovn-nbctl set logical_switch_port $nfsw-p4 \
     options:receive_multicast=false options:lsp_learn_fdb=false \
     options:is-nf=true options:nf-linked-port=$nfsw-p3

-check ovn-nbctl nf-add nf0 $nfsw-p1 $nfsw-p2
-check ovn-nbctl nf-add nf1 $nfsw-p3 $nfsw-p4
+check ovn-nbctl nf-add nf0 1 $nfsw-p1 $nfsw-p2
+check ovn-nbctl nf-add nf1 2 $nfsw-p3 $nfsw-p4
 nf0_uuid=$(fetch_column nb:network_function _uuid name=nf0)
 nf1_uuid=$(fetch_column nb:network_function _uuid name=nf1)
 AT_CHECK(
diff --git a/tests/ovn.at b/tests/ovn.at
index 445a74ce5..3babe1636 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -35816,7 +35816,7 @@ check ovs-vsctl add-port br-int ls0-hv -- set Interface 
ls0-hv external-ids:ifac
 check ovn-nbctl lr-add lr0

 check ovn-nbctl ls-add ls0
-check ovn-nbctl lsp-add ls0 ls0-lr0
+check ovn-nbctl lsp-add ls0 ls0-lr0
 check ovn-nbctl lsp-set-type ls0-lr0 router
 check ovn-nbctl lsp-set-addresses ls0-lr0 router
 check ovn-nbctl lrp-add lr0 lr0-ls0 00:00:00:00:00:01 10.0.0.1
@@ -43563,7 +43563,7 @@ create_logical_topology() {
     check ovn-nbctl set logical_switch_port $sw-nf-p2 \
         options:receive_multicast=false options:lsp_learn_mac=false \
         options:is-nf=true options:nf-linked-port=$sw-nf-p1
-    check ovn-nbctl nf-add nf0 $sw-nf-p1 $sw-nf-p2
+    check ovn-nbctl nf-add nf0 1 $sw-nf-p1 $sw-nf-p2
     check ovn-nbctl nfg-add nfg0 1 inline nf0
     check ovn-nbctl pg-add pg0 $sw-p1
     check ovn-nbctl acl-add pg0 from-lport 1002 "inport == @pg0 && ip4.dst == 
192.168.0.12" allow-related nfg0
@@ -43753,7 +43753,7 @@ create_logical_topology() {
     check ovn-nbctl set logical_switch_port $sw-nf-p2 \
         options:receive_multicast=false options:lsp_learn_mac=false \
         options:is-nf=true options:nf-linked-port=$sw-nf-p1
-    check ovn-nbctl nf-add nf0 $sw-nf-p1 $sw-nf-p2
+    check ovn-nbctl nf-add nf0 1 $sw-nf-p1 $sw-nf-p2
     check ovn-nbctl nfg-add nfg0 1 inline nf0
     check ovn-nbctl pg-add pg0 $sw-p1
     check ovn-nbctl acl-add pg0 to-lport 1002 "outport == @pg0 && ip4.src == 
192.168.0.12" allow-related nfg0
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index fc601dd1b..a10f3e591 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -19417,7 +19417,7 @@ check ovn-nbctl set logical_switch_port child-4 
options:receive_multicast=false

 AS_BOX([Test-1: Single NF without health check])

-check ovn-nbctl nf-add nf0 nf-p1 nf-p2
+check ovn-nbctl nf-add nf0 1 nf-p1 nf-p2
 nf0_uuid=$(fetch_column nb:network_function _uuid name=nf0)
 check ovn-nbctl nfg-add nfg0 1 inline nf0
 nfg_uuid=$(fetch_column nb:network_function_group _uuid name=nfg0)
@@ -19519,7 +19519,7 @@ validate_single_nf_no_health_check "server" "client" 
"192.168.1.10" "Outbound"
 AS_BOX([Test-2: Two NFs with health check config enabled])

 # Add second NF
-check ovn-nbctl nf-add nf1 nf-p3 nf-p4
+check ovn-nbctl nf-add nf1 2 nf-p3 nf-p4
 nf1_uuid=$(fetch_column nb:network_function _uuid name=nf1)

 # Add bridge for nf1
diff --git a/utilities/ovn-nbctl.8.xml b/utilities/ovn-nbctl.8.xml
index 7df902944..253f6d8fc 100644
--- a/utilities/ovn-nbctl.8.xml
+++ b/utilities/ovn-nbctl.8.xml
@@ -475,16 +475,17 @@
     <h2>Network Function Commands</h2>

     <dl>
-      <dt>[<code>--may-exist</code>] <code>nf-add</code> <var>nf</var> 
<var>inport</var> <var>outport</var></dt>
+      <dt>[<code>--may-exist</code>] <code>nf-add</code> <var>nf</var> 
<var>id</var> <var>inport</var> <var>outport</var></dt>
       <dd>
         <p>
-          Creates a new network function named <var>nf</var> with logical
-          switch ports <var>inport</var> and <var>outport</var>. Both the
-          ports must be on the same logical switch and must be already
-          created. When used in an ACL action, traffic matching the ACL
-          are redirected to the <var>inport</var> if it is from-lport ACL
-          and to the <var>outport</var> if it is to-lport ACL. The response
-          packets are sent through the same ports in reverse order.
+          Creates a new network function named <var>nf</var> with the specified
+          <var>id</var> (an integer between 1 and 255) and logical switch ports
+          <var>inport</var> and <var>outport</var>. Both the ports must be on
+          the same logical switch and must be already created. When used in an
+          ACL action, traffic matching the ACL are redirected to the
+          <var>inport</var> if it is from-lport ACL and to <var>outport</var>
+          if it is to-lport ACL. The response packets are sent through the same
+          ports in reverse order.
         </p>

         <p>
@@ -1498,7 +1499,7 @@
          The optional argument <var>protocol</var> must be either
          <code>tcp</code>,  <code>udp</code> or <code>sctp</code>. This 
argument
          is useful when a port number is provided as part of the 
<var>vip</var>.
-         If the <var>protocol</var> is unspecified and a port number is 
provided
+         If the <var>protocol</var> is unspecified and a port number is 
provided
          as part of the <var>vip</var>, OVN assumes the <var>protocol</var> to
          be <code>tcp</code>.
         </p>
diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
index cdf6b578a..2b674cad3 100644
--- a/utilities/ovn-nbctl.c
+++ b/utilities/ovn-nbctl.c
@@ -393,7 +393,7 @@ Network function group commands:\n\
                             network-function-group\n\
 \n\
 Network function commands:\n\
-  nf-add NETWORK-FUNCTION PORT-IN PORT-OUT\n\
+  nf-add NETWORK-FUNCTION ID PORT-IN PORT-OUT\n\
                            create a network-function\n\
   nf-del NETWORK-FUNCTION  delete a network-function\n\
   nf-list                  print all network-functions\n\
@@ -2483,6 +2483,7 @@ nbctl_pre_nf_add(struct ctl_context *ctx)

     ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_name);
     ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name);
+    ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_id);
     ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_inport);
     ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_outport);
 }
@@ -2495,17 +2496,25 @@ nbctl_nf_add(struct ctl_context *ctx)

     bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL;

-    char * error = lsp_by_name_or_uuid(ctx, ctx->argv[2], true, &lsp_in);
+    char * error = lsp_by_name_or_uuid(ctx, ctx->argv[3], true, &lsp_in);
     if (error) {
         ctx->error = error;
         return;
     }
-    error = lsp_by_name_or_uuid(ctx, ctx->argv[3], true, &lsp_out);
+    error = lsp_by_name_or_uuid(ctx, ctx->argv[4], true, &lsp_out);
     if (error) {
         ctx->error = error;
         return;
     }

+    /* Validate and parse ID */
+    int64_t nf_id = 0;
+    if (!ovs_scan(ctx->argv[2], "%"SCNd64, &nf_id)
+            || nf_id < 1 || nf_id > 255) {
+        ctl_error(ctx, "network-function id must be between 1 and 255");
+        return;
+    }
+
     const char *nf_name = ctx->argv[1];

     /* Check if network function already exists */
@@ -2528,6 +2537,9 @@ nbctl_nf_add(struct ctl_context *ctx)
         nbrec_network_function_set_name(nf, nf_name);
     }

+    /* Set ID */
+    nbrec_network_function_set_id(nf, nf_id);
+
     /* Set/update the ports */
     nbrec_network_function_set_inport(nf, lsp_in);
     nbrec_network_function_set_outport(nf, lsp_out);
@@ -2560,6 +2572,7 @@ static void
 nbctl_pre_nf_list(struct ctl_context *ctx)
 {
     ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_name);
+    ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_id);
     ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_inport);
     ovsdb_idl_add_column(ctx->idl, &nbrec_network_function_col_outport);
     ovsdb_idl_add_column(ctx->idl, &nbrec_logical_switch_port_col_name);
@@ -2577,9 +2590,9 @@ nbctl_nf_list(struct ctl_context *ctx)
         const char *linport_name = linport ? linport->name : "<not_set>";
         const char *loutport_name = loutport ? loutport->name : "<not_set>";
         smap_add_format(&nfs, nf->name,
-                        UUID_FMT " (%s) in:%s out:%s",
+                        UUID_FMT " (%s) id:%"PRId64" in:%s out:%s",
                         UUID_ARGS(&nf->header_.uuid),
-                        nf->name, linport_name, loutport_name);
+                        nf->name, nf->id, linport_name, loutport_name);
     }
     const struct smap_node **nodes = smap_sort(&nfs);
     for (size_t i = 0; i < smap_count(&nfs); i++) {
@@ -8877,7 +8890,7 @@ static const struct ctl_command_syntax nbctl_commands[] = 
{
       nbctl_nf_group_del_network_function, NULL, "--if-exists", RW },

     /* network-function commands. */
-    { "nf-add", 3, 3, "NETWORK-FUNCTION PORT-IN PORT-OUT",
+    { "nf-add", 4, 4, "NETWORK-FUNCTION ID PORT-IN PORT-OUT",
       nbctl_pre_nf_add,
       nbctl_nf_add,
       NULL, "--may-exist", RW },
--
2.43.5
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to