On Tue, Sep 23, 2025 at 9:41 AM Indrajitt Valsaraj <
[email protected]> wrote:

> 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 <[email protected]>
>
> ---
> v1:
>  - Address review comments from Mark
> v2:
>  - Rebased patch
> ---
>  NEWS            |   3 +
>  ic/ovn-ic.c     |  53 +++++++++----
>  ovn-nb.xml      |  66 ++++++++++++++---
>  tests/ovn-ic.at | 193 ++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 290 insertions(+), 25 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 4d0c45e4d..4b6742c01 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -2,6 +2,9 @@ Post v25.09.0
>  -------------
>     - Added disable_garp_rarp option to logical_router table in order to
> disable
>       GARP/RARP announcements by all the peer ports of this logical router.
> +   - 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.09.0 - xxx xx xxxx
>  --------------------------
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index 1462b8043..cea64588b 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -1121,26 +1121,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;
>  }
> @@ -1170,7 +1194,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;
>      }
>
> @@ -1527,7 +1552,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 1f5c58490..b96d38e6b 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -3315,7 +3315,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
> @@ -3324,6 +3324,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
> @@ -4352,18 +4374,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 7e2665652..2d92f3adf 100644
> --- a/tests/ovn-ic.at
> +++ b/tests/ovn-ic.at
> @@ -4058,3 +4058,196 @@ OVN_CLEANUP_IC([az1], [az2], [az3])
>  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
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
Thank you Indrajitt,

I have added acks from Mairtin and Lorenzo and merged this into main.

Regards,
Ales
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to