This commit adds the ability for ovn-ic to deny filter routes
learnt/advertised between AZs. This commit also fixes a documentation
error for the ic-route-filter-adv option.

Signed-off-by: Indrajitt Valsaraj <indrajitt.valsa...@nutanix.com>

---
v1:
 - Address review comments from Mark
---
 NEWS            |   3 +
 ic/ovn-ic.c     |  53 +++++++++----
 ovn-nb.xml      |  66 +++++++++++++---
 tests/ovn-ic.at | 194 ++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 291 insertions(+), 25 deletions(-)

diff --git a/NEWS b/NEWS
index 0cce1790d..44ec47b5e 100644
--- a/NEWS
+++ b/NEWS
@@ -41,6 +41,9 @@ Post v25.03.0
    - Added support for running tests from the 'check-kernel' system test target
      under retis by setting OVS_TEST_WITH_RETIS=yes.  See the 'Testing' section
      of the documentation for more details.
+   - Added "ic-route-deny-adv" and "ic-route-deny-learn" options to
+     the Logical_Router/Logical_Router_Port tables to allow users to
+     deny filter advertised/learned IC routes.

 OVN v25.03.0 - 07 Mar 2025
 --------------------------
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index caffa6fe0..71174ae01 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -1109,26 +1109,50 @@ prefix_is_filtered(struct in6_addr *prefix,
 }

 static bool
-prefix_is_deny_listed(const struct smap *nb_options,
-                      struct in6_addr *prefix,
-                      unsigned int plen)
-{
-    const char *filter_name = "ic-route-denylist";
-    const char *denylist = smap_get(nb_options, filter_name);
-    if (!denylist || !denylist[0]) {
-        denylist = smap_get(nb_options, "ic-route-blacklist");
-        if (!denylist || !denylist[0]) {
-            return false;
+prefix_is_deny_filtered(struct in6_addr *prefix,
+                        unsigned int plen,
+                        const struct smap *nb_options,
+                        const struct nbrec_logical_router *nb_lr,
+                        const struct nbrec_logical_router_port *ts_lrp,
+                        bool is_advertisement)
+{
+    struct ds deny_list = DS_EMPTY_INITIALIZER;
+    const char *deny_key = is_advertisement ? "ic-route-deny-adv" :
+                                              "ic-route-deny-learn";
+
+    if (ts_lrp) {
+        const char *lrp_deny_filter = smap_get(&ts_lrp->options, deny_key);
+        if (lrp_deny_filter) {
+            ds_put_format(&deny_list, "%s,", lrp_deny_filter);
+        }
+    }
+
+    if (nb_lr) {
+        const char *lr_deny_filter = smap_get(&nb_lr->options, deny_key);
+        if (lr_deny_filter) {
+            ds_put_format(&deny_list, "%s,", lr_deny_filter);
+        }
+    }
+
+    if (nb_options) {
+        const char *global_deny = smap_get(nb_options, "ic-route-denylist");
+        if (!global_deny || !global_deny[0]) {
+            global_deny = smap_get(nb_options, "ic-route-blacklist");
+        }
+        if (global_deny && global_deny[0]) {
+            ds_put_format(&deny_list, "%s,", global_deny);
         }
     }

     struct sset prefix_set = SSET_INITIALIZER(&prefix_set);
-    sset_from_delimited_string(&prefix_set, denylist, ",");
+    sset_from_delimited_string(&prefix_set, ds_cstr(&deny_list), ",");

     bool denied = false;
     if (!sset_is_empty(&prefix_set)) {
-        denied = find_prefix_in_set(prefix, plen, &prefix_set, filter_name);
+        denied = find_prefix_in_set(prefix, plen, &prefix_set, deny_key);
     }
+
+    ds_destroy(&deny_list);
     sset_destroy(&prefix_set);
     return denied;
 }
@@ -1158,7 +1182,8 @@ route_need_advertise(const char *policy,
         return false;
     }

-    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
+    if (prefix_is_deny_filtered(prefix, plen, nb_options,
+                                nb_lr, ts_lrp, true)) {
         return false;
     }

@@ -1511,7 +1536,7 @@ route_need_learn(const struct nbrec_logical_router *lr,
         return false;
     }

-    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
+    if (prefix_is_deny_filtered(prefix, plen, nb_options, lr, ts_lrp, false)) {
         return false;
     }

diff --git a/ovn-nb.xml b/ovn-nb.xml
index 4a7581807..54f4fd2bd 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -3231,7 +3231,7 @@ or
       <column name="options" key="ic-route-filter-adv">
         <p>
           This option expects list of CIDRs delimited by "," that's present
-          in the Logical Router. A route will not be advertised if the
+          in the Logical Router. A route will be advertised if the
           route's prefix belongs to any of the CIDRs listed.

           This allows to filter CIDR prefixes in the process of advertising
@@ -3240,6 +3240,28 @@ or
       </column>

       <column name="options" key="ic-route-filter-learn">
+        <p>
+          This option expects list of CIDRs delimited by "," that's present
+          in the Logical Router. A route will be learned if the
+          route's prefix belongs to any of the CIDRs listed.
+
+          This allows to filter CIDR prefixes in the process of learning
+          routes in <code>ovn-ic</code> daemon.
+        </p>
+      </column>
+
+      <column name="options" key="ic-route-deny-adv">
+        <p>
+          This option expects list of CIDRs delimited by "," that's present
+          in the Logical Router. A route will not be advertised if the
+          route's prefix belongs to any of the CIDRs listed.
+
+          This allows to filter CIDR prefixes in the process of advertising
+          routes in <code>ovn-ic</code> daemon.
+        </p>
+      </column>
+
+      <column name="options" key="ic-route-deny-learn">
         <p>
           This option expects list of CIDRs delimited by "," that's present
           in the Logical Router. A route will not be learned if the
@@ -4236,18 +4258,40 @@ or
            This allows to filter CIDR prefixes in the process of advertising
            routes in <code>ovn-ic</code> daemon.
          </p>
-       </column>
+      </column>

-       <column name="options" key="ic-route-filter-learn">
-         <p>
-           This option expects list of CIDRs delimited by "," that's present
-           in the Logical Router Port. A route will be learned if the
-           route's prefix belongs to any of the CIDRs listed.
+      <column name="options" key="ic-route-filter-learn">
+        <p>
+          This option expects list of CIDRs delimited by "," that's present
+          in the Logical Router Port. A route will be learned if the
+          route's prefix belongs to any of the CIDRs listed.

-           This allows to filter CIDR prefixes in the process of learning
-           routes in <code>ovn-ic</code> daemon.
-         </p>
-       </column>
+          This allows to filter CIDR prefixes in the process of learning
+          routes in <code>ovn-ic</code> daemon.
+        </p>
+      </column>
+
+      <column name="options" key="ic-route-deny-adv">
+        <p>
+          This option expects list of CIDRs delimited by "," that's present
+          in the Logical Router Port. A route will not be advertised if the
+          route's prefix belongs to any of the CIDRs listed.
+
+          This allows to filter CIDR prefixes in the process of advertising
+          routes in <code>ovn-ic</code> daemon.
+        </p>
+      </column>
+
+      <column name="options" key="ic-route-deny-learn">
+        <p>
+          This option expects list of CIDRs delimited by "," that's present in
+          the Logical Router Port. A route will not be learned if the
+          route's prefix belongs to any of the CIDRs listed.
+
+          This allows to filter CIDR prefixes in the process of learning
+          routes in <code>ovn-ic</code> daemon.
+        </p>
+      </column>
     </group>

     <group title="Attachment">
diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at
index 49a409015..b866f9b8b 100644
--- a/tests/ovn-ic.at
+++ b/tests/ovn-ic.at
@@ -3640,6 +3640,200 @@ OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list 
lr11 | grep 2001 |
 2001:db12::/64 fe80:10::2
 ])

+OVN_CLEANUP_IC([az1], [az2])
+AT_CLEANUP
+])
+
+OVN_FOR_EACH_NORTHD([
+AT_SETUP([ovn-ic -- prefix filter -- deny route adv])
+ovn_init_ic_db
+ovn-ic-nbctl ts-add ts1
+for i in 1 2; do
+    ovn_start az$i
+    ovn_as az$i
+    check ovn-nbctl set nb_global . options:ic-route-learn=true
+    check ovn-nbctl set nb_global . options:ic-route-adv=true
+done
+
+# Create routers and connect to transit switch
+for i in 1 2; do
+    ovn_as az$i
+    lr=lr1$i
+    check ovn-nbctl lr-add $lr
+    lrp=lrp-$lr-ts1
+    lsp=lsp-ts1-$lr
+    check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:ab:0$i 169.254.101.$i/24 
fe80:10::$i/64
+    check ovn-nbctl lsp-add ts1 $lsp \
+        -- lsp-set-addresses $lsp router \
+        -- lsp-set-type $lsp router \
+        -- lsp-set-options $lsp router-port=$lrp
+done
+
+# Add directly connected routes to lr12 (first two test prefixes reused)
+ovn_as az2 check ovn-nbctl lrp-add lr12 lrp-lr12-1 aa:aa:aa:aa:cc:01 
"192.168.100.1/24" "2001:db12::1/64"
+ovn_as az2 check ovn-nbctl lrp-add lr12 lrp-lr12-2 aa:aa:aa:aa:cc:02 
"192.168.200.1/24" "2001:db22::1/64"
+
+# Sync IC DB
+check ovn-ic-nbctl --wait=sb sync
+
+# Validate lr11 learns both IPv4 and IPv6 routes from lr12
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E 
'192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.100.0/24 169.254.101.2
+192.168.200.0/24 169.254.101.2
+2001:db12::/64 fe80:10::2
+2001:db22::/64 fe80:10::2
+])
+
+# Set deny-adv on lrp-lr12-ts1 for 192.168.100.0/24
+ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 
options:ic-route-deny-adv=192.168.100.0/24
+
+# Only 192.168.200.0/24 should now be learned
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | 
grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.200.0/24 169.254.101.2
+])
+
+# Add IPv6 deny prefix too
+ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 
options:ic-route-deny-adv="192.168.100.0/24,2001:db12::/64"
+
+# Only 2001:db22::/64 should be learned now
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | 
grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+2001:db22::/64 fe80:10::2
+])
+
+# Remove deny-adv and validate all are learned again
+ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options 
ic-route-deny-adv
+
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep learned | 
awk '{print $1, $2}' | sort], [0], [dnl
+192.168.100.0/24 169.254.101.2
+192.168.200.0/24 169.254.101.2
+2001:db12::/64 fe80:10::2
+2001:db22::/64 fe80:10::2
+])
+
+# --- Test ic-route-deny-learn ---
+
+# Set deny-learn on lrp-lr11-ts1 for 192.168.200.0/24 and 2001:db22::/64
+ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 
options:ic-route-deny-learn="192.168.200.0/24,2001:db22::/64"
+
+# Now lr11 should only learn 192.168.100.0/24 and 2001:db12::/64
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E 
'192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.100.0/24 169.254.101.2
+2001:db12::/64 fe80:10::2
+])
+
+# Remove deny-learn and confirm full route learning resumes
+ovn_as az1 check ovn-nbctl remove logical_router_port lrp-lr11-ts1 options 
ic-route-deny-learn
+
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E 
'192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.100.0/24 169.254.101.2
+192.168.200.0/24 169.254.101.2
+2001:db12::/64 fe80:10::2
+2001:db22::/64 fe80:10::2
+])
+
+# --- Test setting deny options on logical router ---
+
+# Set deny-adv on lr12 for 192.168.100.0/24
+ovn_as az2 check ovn-nbctl set logical_router lr12 
options:ic-route-deny-adv="192.168.100.0/24"
+
+# Sync again after router option is applied
+check ovn-ic-nbctl --wait=sb sync
+
+# Only 192.168.200.0/24 should now be learned
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | 
grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.200.0/24 169.254.101.2
+])
+
+# Set deny-learn on lr11 for 2001:db22::/64
+ovn_as az1 check ovn-nbctl set logical_router lr11 
options:ic-route-deny-learn="2001:db22::/64"
+
+# Only 2001:db12::/64 should now be learned
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | 
grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+2001:db12::/64 fe80:10::2
+])
+
+# Clean up router-level options
+ovn_as az2 check ovn-nbctl remove logical_router lr12 options ic-route-deny-adv
+ovn_as az1 check ovn-nbctl remove logical_router lr11 options 
ic-route-deny-learn
+
+# Confirm all routes are back
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep learned | 
awk '{print $1, $2}' | sort], [0], [dnl
+192.168.100.0/24 169.254.101.2
+192.168.200.0/24 169.254.101.2
+2001:db12::/64 fe80:10::2
+2001:db22::/64 fe80:10::2
+])
+
+# --- Test ic-route-denylist (global option) ---
+
+# Set global denylist to block 192.168.100.0/24 and 2001:db12::/64
+ovn_as az2 check ovn-nbctl set nb_global . 
options:ic-route-denylist="192.168.100.0/24,2001:db12::/64"
+
+# Now lr11 should only learn 192.168.200.0/24 and 2001:db22::/64
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E 
'192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.200.0/24 169.254.101.2
+2001:db22::/64 fe80:10::2
+])
+
+# Remove global denylist
+ovn_as az2 check ovn-nbctl remove nb_global . options ic-route-denylist
+
+# Confirm all routes are learned again
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E 
'192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.100.0/24 169.254.101.2
+192.168.200.0/24 169.254.101.2
+2001:db12::/64 fe80:10::2
+2001:db22::/64 fe80:10::2
+])
+
+# --- Test combination of deny options ---
+
+# Set all deny filters
+ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 
options:ic-route-deny-adv="192.168.100.0/24"
+ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 
options:ic-route-deny-learn="192.168.200.0/24"
+ovn_as az2 check ovn-nbctl set nb_global . 
options:ic-route-denylist="2001:db12::/64"
+
+# Validate only 2001:db22::/64 is learned
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E 
'192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+2001:db22::/64 fe80:10::2
+])
+
+# Clean up for interaction tests
+ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options 
ic-route-deny-adv
+ovn_as az1 check ovn-nbctl remove logical_router_port lrp-lr11-ts1 options 
ic-route-deny-learn
+ovn_as az2 check ovn-nbctl remove nb_global . options ic-route-denylist
+
+# --- Test interactions between different filter options ---
+
+# Test ic-route-filter-adv vs ic-route-deny-adv precedence
+# Set both filter-adv (allow) and deny-adv (deny) for same CIDR - deny should 
take precedence
+ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 
options:ic-route-filter-adv="192.168.100.0/24,192.168.200.0/24"
+ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 
options:ic-route-deny-adv="192.168.100.0/24"
+
+# Only 192.168.200.0/24 should be learned (192.168.100.0/24 denied despite 
being in filter-adv)
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | 
grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+192.168.200.0/24 169.254.101.2
+])
+
+# Clean up
+ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options 
ic-route-filter-adv
+ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options 
ic-route-deny-adv
+
+# Test cross-router interaction: filter-adv on lr12 vs deny-learn on lr11
+# lr12 allows advertising 192.168.100.0/24, but lr11 denies learning it
+ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 
options:ic-route-filter-adv="192.168.100.0/24"
+ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 
options:ic-route-deny-learn="192.168.100.0/24"
+
+# 192.168.100.0/24 should not be learned (deny-learn takes precedence over 
filter-adv)
+# No routes should be learned since only 192.168.100.0/24 is allowed to be 
advertised but it's denied for learning
+OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 | 
grep learned | wc -l], [0], [0
+])
+
+# Clean up interaction tests
+ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options 
ic-route-filter-adv
+ovn_as az1 check ovn-nbctl remove logical_router_port lrp-lr11-ts1 options 
ic-route-deny-learn
+
+
 OVN_CLEANUP_IC([az1], [az2])
 AT_CLEANUP
 ])
--
2.39.3
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to