diff mbox series

[ovs-dev,v0] ovn-ic: Add support for route prefix filter.

Message ID 20241126205747.2373487-1-guilherme.paulo@luizalabs.com
State Changes Requested
Headers show
Series [ovs-dev,v0] ovn-ic: Add support for route prefix filter. | expand

Commit Message

Paulo Guilherme da Silva Nov. 26, 2024, 8:57 p.m. UTC
From: Paulo Guilherme da Silva <silva.pauloguilherme@gmail.com>

This commit adds the ability for ovn-ic to filter routes between VPCs.
In use cases where the user is using vpc-peering(route tag) handling 
multiple points of redistribution, when we connect more than one TS in 
the same Logical Router it is essential that we have control over which 
routes will be filtered or advertised by transit switch.

Signed-off-by: Paulo Guilherme da Silva <silva.pauloguilherme@gmail.com>
Co-authored-by: Roberto Bartzen Acosta <rbartzen@gmail.com>
---
 .../workflows/ovn-fake-multinode-tests.yml    |   2 +-
 ic/ovn-ic.c                                   |  71 ++++--
 ovn-nb.xml                                    |  44 ++++
 tests/multinode-macros.at                     |  81 +++++++
 tests/multinode.at                            | 223 ++++++++++++++++++
 5 files changed, 401 insertions(+), 20 deletions(-)

Comments

Numan Siddique Dec. 20, 2024, 10:22 p.m. UTC | #1
On Wed, Nov 27, 2024 at 3:43 AM Paulo Guilherme da Silva
<silva.pauloguilherme@gmail.com> wrote:
>
> From: Paulo Guilherme da Silva <silva.pauloguilherme@gmail.com>
>
> This commit adds the ability for ovn-ic to filter routes between VPCs.
> In use cases where the user is using vpc-peering(route tag) handling
> multiple points of redistribution, when we connect more than one TS in
> the same Logical Router it is essential that we have control over which
> routes will be filtered or advertised by transit switch.
>
> Signed-off-by: Paulo Guilherme da Silva <silva.pauloguilherme@gmail.com>
> Co-authored-by: Roberto Bartzen Acosta <rbartzen@gmail.com>

Thanks for the patch.

Please see below for a few comments.

Overall the patch LGTM.

Numan

> ---
>  .../workflows/ovn-fake-multinode-tests.yml    |   2 +-
>  ic/ovn-ic.c                                   |  71 ++++--
>  ovn-nb.xml                                    |  44 ++++
>  tests/multinode-macros.at                     |  81 +++++++
>  tests/multinode.at                            | 223 ++++++++++++++++++
>  5 files changed, 401 insertions(+), 20 deletions(-)
>
> diff --git a/.github/workflows/ovn-fake-multinode-tests.yml b/.github/workflows/ovn-fake-multinode-tests.yml
> index bf966299d..42d99830f 100644
> --- a/.github/workflows/ovn-fake-multinode-tests.yml
> +++ b/.github/workflows/ovn-fake-multinode-tests.yml
> @@ -149,7 +149,7 @@ jobs:
>
>      - name: Start basic cluster
>        run: |
> -        sudo -E CHASSIS_COUNT=4 GW_COUNT=4 ./ovn_cluster.sh start
> +        sudo -E ENABLE_SSL=no CENTRAL_COUNT=4 CHASSIS_COUNT=4 GW_COUNT=4 ./ovn_cluster.sh start

For the next version of this patch, can you please trigger a fake
multinode test in your github branch and share the
CI run results in the commit message ?


>          sudo podman exec -it ovn-central-az1-1 ovn-nbctl show
>          sudo podman exec -it ovn-central-az1-1 ovn-appctl -t ovn-northd version
>          sudo podman exec -it ovn-chassis-1 ovn-appctl -t ovn-controller version
> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> index c95b556f8..907184c38 100644
> --- a/ic/ovn-ic.c
> +++ b/ic/ovn-ic.c
> @@ -1030,21 +1030,45 @@ prefix_is_link_local(struct in6_addr *prefix, unsigned int plen)
>  }
>
>  static bool
> -prefix_is_deny_listed(const struct smap *nb_options,
> -                      struct in6_addr *prefix,
> -                      unsigned int plen)
> +prefix_is_filtered(const struct smap *nb_options,
> +                   struct in6_addr *prefix,
> +                   unsigned int plen,
> +                   const struct nbrec_logical_router *nb_lr,
> +                   const struct nbrec_logical_router_port *ts_lrp,
> +                   bool is_advertisement)
>  {
> +    struct ds filter_list = DS_EMPTY_INITIALIZER;
> +    const char *filter_direction = is_advertisement ? "ic-route-filter-adv" :\
> +        "ic-route-filter-learn";
>      const char *denylist = smap_get(nb_options, "ic-route-denylist");
>      if (!denylist || !denylist[0]) {
>          denylist = smap_get(nb_options, "ic-route-blacklist");
> -        if (!denylist || !denylist[0]) {
> -            return false;
> +    }
> +    if (denylist) {
> +        ds_put_format(&filter_list, "%s,", denylist);
> +    }
> +    if (ts_lrp) {
> +        const char *lrp_route_filter = smap_get(&ts_lrp->options,
> +                                         filter_direction);

nit: Please fix the indentation.

> +        if (lrp_route_filter) {
> +            ds_put_format(&filter_list, "%s,", lrp_route_filter);
>          }
>      }
> +    const char *lr_route_filter = smap_get(&nb_lr->options,
> +                                           filter_direction);

nit: Please fix the indentation.

> +    if (lr_route_filter) {
> +        ds_put_format(&filter_list, "%s,", lr_route_filter);
> +    }
> +
> +    if (!filter_list.length) {

I think you can use the function
> +        ds_destroy(&filter_list);
> +        return false;
> +    }
> +
>      struct in6_addr bl_prefix;
>      unsigned int bl_plen;
>      char *cur, *next, *start;
> -    next = start = xstrdup(denylist);
> +    next = start = xstrdup(ds_cstr(&filter_list));
>      bool matched = false;
>      while ((cur = strsep(&next, ",")) && *cur) {
>          if (!ip46_parse_cidr(cur, &bl_prefix, &bl_plen)) {

If ip46_parse_cidr() fails, there is a below warning which needs to be updated
appropriately.  With this patch,  the while loop now parses not just
the denylist
but a set of filters.

VLOG_WARN_RL(&rl, "Bad format in nb_global options:"
"ic-route-denylist: %s. CIDR expected.", cur);

> @@ -1087,6 +1111,7 @@ prefix_is_deny_listed(const struct smap *nb_options,
>          break;
>      }
>      free(start);
> +    ds_destroy(&filter_list);
>      return matched;
>  }
>
> @@ -1094,7 +1119,9 @@ static bool
>  route_need_advertise(const char *policy,
>                       struct in6_addr *prefix,
>                       unsigned int plen,
> -                     const struct smap *nb_options)
> +                     const struct smap *nb_options,
> +                     const struct nbrec_logical_router *nb_lr,
> +                     const struct nbrec_logical_router_port *ts_lrp)
>  {
>      if (!smap_get_bool(nb_options, "ic-route-adv", false)) {
>          return false;
> @@ -1113,7 +1140,7 @@ route_need_advertise(const char *policy,
>          return false;
>      }
>
> -    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
> +    if (prefix_is_filtered(nb_options, prefix, plen, nb_lr, ts_lrp, true)) {
>          return false;
>      }
>      return true;
> @@ -1162,7 +1189,8 @@ add_static_to_routes_ad(
>      const struct nbrec_logical_router *nb_lr,
>      const struct lport_addresses *nexthop_addresses,
>      const struct smap *nb_options,
> -    const char *route_tag)
> +    const char *route_tag,
> +    const struct nbrec_logical_router_port *ts_lrp)
>  {
>      struct in6_addr prefix, nexthop;
>      unsigned int plen;
> @@ -1171,7 +1199,8 @@ add_static_to_routes_ad(
>          return;
>      }
>
> -    if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options)) {
> +    if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options,
> +                              nb_lr, ts_lrp)) {
>          return;
>      }
>
> @@ -1212,7 +1241,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
>                           const struct lport_addresses *nexthop_addresses,
>                           const struct smap *nb_options,
>                           const struct nbrec_logical_router *nb_lr,
> -                         const char *route_tag)
> +                         const char *route_tag,
> +                         const struct nbrec_logical_router_port *ts_lrp)
>  {
>      struct in6_addr prefix, nexthop;
>      unsigned int plen;
> @@ -1220,7 +1250,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
>          return;
>      }
>
> -    if (!route_need_advertise(NULL, &prefix, plen, nb_options)) {
> +    if (!route_need_advertise(NULL, &prefix, plen, nb_options,
> +                              nb_lr, ts_lrp)) {
>          VLOG_DBG("Route ad: skip network %s of lrp %s.",
>                   network, nb_lrp->name);
>          return;
> @@ -1274,7 +1305,8 @@ static bool
>  route_need_learn(const struct nbrec_logical_router *lr,
>                   const struct icsbrec_route *isb_route,
>                   struct in6_addr *prefix, unsigned int plen,
> -                 const struct smap *nb_options)
> +                 const struct smap *nb_options,
> +                 const struct nbrec_logical_router_port *ts_lrp)
>  {
>      if (!smap_get_bool(nb_options, "ic-route-learn", false)) {
>          return false;
> @@ -1289,7 +1321,7 @@ route_need_learn(const struct nbrec_logical_router *lr,
>          return false;
>      }
>
> -    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
> +    if (prefix_is_filtered(nb_options, prefix, plen, lr, ts_lrp, false)) {
>          return false;
>      }
>
> @@ -1427,7 +1459,7 @@ sync_learned_routes(struct ic_context *ctx,
>                  continue;
>              }
>              if (!route_need_learn(ic_lr->lr, isb_route, &prefix, plen,
> -                                  &nb_global->options)) {
> +                                  &nb_global->options, lrp)) {
>                  continue;
>              }
>
> @@ -1613,7 +1645,8 @@ build_ts_routes_to_adv(struct ic_context *ctx,
>                         struct lport_addresses *ts_port_addrs,
>                         const struct nbrec_nb_global *nb_global,
>                         const char *ts_route_table,
> -                       const char *route_tag)
> +                       const char *route_tag,
> +                       const struct nbrec_logical_router_port *ts_lrp)
>  {
>      const struct nbrec_logical_router *lr = ic_lr->lr;
>
> @@ -1636,7 +1669,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,
>          } else if (!strcmp(ts_route_table, nb_route->route_table)) {
>              /* It may be a route to be advertised */
>              add_static_to_routes_ad(routes_ad, nb_route, lr, ts_port_addrs,
> -                                    &nb_global->options, route_tag);
> +                                    &nb_global->options, route_tag, ts_lrp);
>          }
>      }
>
> @@ -1648,7 +1681,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,
>                  add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp,
>                                           ts_port_addrs,
>                                           &nb_global->options,
> -                                         lr, route_tag);
> +                                         lr, route_tag, ts_lrp);
>              }
>          } else {
>              /* The router port of the TS port is ignored. */
> @@ -1712,7 +1745,7 @@ collect_lr_routes(struct ic_context *ctx,
>              route_tag = "";
>          }
>          build_ts_routes_to_adv(ctx, ic_lr, routes_ad, &ts_port_addrs,
> -                               nb_global, route_table, route_tag);
> +                               nb_global, route_table, route_tag, lrp);
>          destroy_lport_addresses(&ts_port_addrs);
>      }
>  }
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 5114bbc2e..9fdc3e348 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -2946,6 +2946,28 @@ or
>          option is not present the limit is not set and the zone limit is
>          derived from OvS default datapath limit.
>        </column>
> +
> +      <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
> +          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-filter-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
> +          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="Common Columns">
> @@ -3705,6 +3727,28 @@ or
>            learned by the <code>ovn-ic</code> daemon.
>          </p>
>        </column>
> +      <column name="options" key="ic-route-filter-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-filter-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/multinode-macros.at b/tests/multinode-macros.at
> index 698d2c625..3babf5242 100644
> --- a/tests/multinode-macros.at
> +++ b/tests/multinode-macros.at
> @@ -71,6 +71,7 @@ m_central_as () {
>  }
>
>  check_fake_multinode_setup() {
> +    skip_fake_node_multi_az_setup
>      check m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
>      AT_CHECK([m_as ovn-chassis-1 ovn-appctl -t ovn-controller version], [0], [ignore])
>      AT_CHECK([m_as ovn-chassis-2 ovn-appctl -t ovn-controller version], [0], [ignore])
> @@ -78,6 +79,86 @@ check_fake_multinode_setup() {
>      AT_CHECK([m_as ovn-gw-1 ovn-appctl -t ovn-controller version], [0], [ignore])
>  }
>
> +# Based on Tiago Pires patch (multinode: Adding multinode ovn-ic test)

I see that you have taken the code from this patch -
https://patchwork.ozlabs.org/project/ovn/patch/20241022183342.105084-1-tiago.pires@luizalabs.com/

It's worth checking with Tiago if he is fine with it.  Since that
patch has some comments from Dumitru,  those need to be addressed.

Instead of copying the code from that patch,  I'd suggest that you
take over that patch if Tiago is fine with it, address the review
comments and make yourself the co-author of it.
Does that sound good ?

@Tiago - Are you fine with this ?  Or do you plan to address the
review comments from Dumitru and submit v5 ?



> +skip_fake_node_multi_az_setup() {
> +    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> +    if [[ $? == 0 ]] ; then
> +        AT_CHECK([exit 77])
> +    fi
> +}
> +
> +check_fake_node_multi_az_setup() {
> +    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> +    if [[ $? != 0 ]] ; then
> +        AT_CHECK([exit 77])
> +    fi
> +
> +    # Check if the fake multinode setup is using SSL, it will
> +    # skip if it is enabled. The cleanup will break the setup,
> +    # so it is recommended to use without SSL in order to
> +    # test the OVN IC with fake multinode setup.
> +    m_as ovn-chassis-1 ovs-vsctl list open | grep "ssl:"
> +    if [[ $? == 0 ]] ; then
> +        AT_CHECK([exit 77])
> +    fi
> +}
> +
> +check_fake_multinode_setup_by_az() {
> +    check_fake_node_multi_az_setup
> +
> +    m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
> +    m_as ovn-central-az2-1 ovn-nbctl --wait=sb sync
> +    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> +
> +    for c in $1
> +    do
> +        m_as $c ovn-appctl -t ovn-controller version
> +    done
> +}
> +
> +cleanup_multinode_resources_by_az() {
> +    check_fake_node_multi_az_setup
> +    m_as ovn-central-az1-1 rm -f /etc/ovn/ovnnb_db.db
> +    m_as ovn-central-az1-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> +    m_as ovn-central-az2-1 rm -f /etc/ovn/ovnnb_db.db
> +    m_as ovn-central-az2-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> +    m_as ovn-central-az3-1 rm -f /etc/ovn/ovnnb_db.db
> +    m_as ovn-central-az3-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> +    check m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
> +    check m_as ovn-central-az2-1 ovn-nbctl --wait=sb sync
> +    check m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> +
> +    for c in $1
> +    do
> +        m_as $c ovs-vsctl del-br br-int
> +        m_as $c ip --all netns delete
> +    done
> +}
> +
> +configure_multinode_az() {
> +    # Configure OVN IC by AZ
> +    check m_as ovn-central-az1-1 ovn-nbctl set-connection ptcp:6641
> +    check m_as ovn-central-az1-1 ovn-sbctl set-connection ptcp:6642
> +    check m_as ovn-central-az1-1 ovn-nbctl set NB_Global . name=ovn-central-az1-1
> +    check m_as ovn-central-az1-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
> +                            options:ic-route-learn=true
> +    check m_as ovn-central-az2-1 ovn-nbctl set-connection ptcp:6641
> +    check m_as ovn-central-az2-1 ovn-sbctl set-connection ptcp:6642
> +    check m_as ovn-central-az2-1 ovn-nbctl set NB_Global . name=ovn-central-az2-1
> +    check m_as ovn-central-az2-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
> +                            options:ic-route-learn=true
> +    check m_as ovn-central-az3-1 ovn-nbctl set-connection ptcp:6641
> +    check m_as ovn-central-az3-1 ovn-sbctl set-connection ptcp:6642
> +    check m_as ovn-central-az3-1 ovn-nbctl set NB_Global . name=ovn-central-az3-1
> +    check m_as ovn-central-az3-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
> +                            options:ic-route-learn=true
> +
> +    # Configure OVN IC Gateway
> +    check m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-is-interconn=true
> +    check m_as ovn-gw-2 ovs-vsctl set open . external-ids:ovn-is-interconn=true
> +    check m_as ovn-gw-3 ovs-vsctl set open . external-ids:ovn-is-interconn=true
> +}
> +
>  cleanup_multinode_resources() {
>      m_as ovn-central-az1-1 rm -f /etc/ovn/ovnnb_db.db
>      m_as ovn-central-az1-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> diff --git a/tests/multinode.at b/tests/multinode.at
> index a45dc55cc..b7bd38eef 100644
> --- a/tests/multinode.at
> +++ b/tests/multinode.at
> @@ -2582,3 +2582,226 @@ Connected to 10.0.2.4 (10.0.2.4) port 8080
>  fi
>
>  AT_CLEANUP
> +=======

I think there is no need for the above line - "======="


Thanks
Numan

> +AT_SETUP([ovn multinode - ovn-ic - inter-AZ IPv4/IPv6])
> +
> +# Based on Tiago Pires patch (multinode: Adding multinode ovn-ic test)
> +
> +# Check that ovn-fake-multinode setup is up and running - requires additional nodes
> +check_fake_multinode_setup_by_az 'ovn-chassis-1 ovn-chassis-2 ovn-chassis-3 ovn-gw-1 ovn-gw-2 ovn-gw-3'
> +
> +# Delete the multinode NB and OVS resources before starting the test.
> +cleanup_multinode_resources_by_az 'ovn-chassis-1 ovn-chassis-2 ovn-chassis-3 ovn-gw-1 ovn-gw-2 ovn-gw-3'
> +
> +# Configure OVN IC by AZ
> +configure_multinode_az
> +
> +# Test Inter-AZ routing
> +
> +# Create the Transit Switch
> +m_as ovn-central-az1-1 ovn-ic-nbctl ts-add ts-1
> +
> +# AZ1 - Create one logical switch with one port
> +check m_as ovn-central-az1-1 ovn-nbctl ls-add sw1-az1
> +check m_as ovn-central-az1-1 ovn-nbctl lsp-add sw1-az1 sw1-az1-port1
> +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-addresses sw1-az1-port1 "40:54:00:00:01:01 10.0.1.3 2001::3"
> +
> +# AZ1 - Create a logical router and attach the logical switch
> +check m_as ovn-central-az1-1 ovn-nbctl lr-add lr1
> +check m_as ovn-central-az1-1 ovn-nbctl lrp-add lr1 lr1-sw1-az1 00:00:00:00:ff:01 10.0.1.1/24 2001::1/64
> +check m_as ovn-central-az1-1 ovn-nbctl lsp-add sw1-az1 sw1-az1-lr1
> +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-type sw1-az1-lr1 router
> +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-addresses sw1-az1-lr1 router
> +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-options sw1-az1-lr1 router-port=lr1-sw1-az1
> +
> +# AZ1 - Create the LRP, LSP and interconnect to the Transit Switch
> +check m_as ovn-central-az1-1 ovn-nbctl lrp-add lr1 lr1-ts-1 00:00:00:00:00:01 169.254.251.1/24 fe80:10::1/64
> +check m_as ovn-central-az1-1 ovn-nbctl lrp-set-gateway-chassis lr1-ts-1 ovn-gw-1
> +check m_as ovn-central-az1-1 ovn-nbctl lsp-add ts-1 lr1-lsp1 -- \
> +    lsp-set-addresses lr1-lsp1 router -- \
> +    lsp-set-type lr1-lsp1 router -- \
> +    lsp-set-options lr1-lsp1 router-port=lr1-ts-1
> +
> +m_as ovn-chassis-1 ip link del sw1-az1-p1-p
> +m_as ovn-chassis-1 /data/create_fake_vm.sh sw1-az1-port1 sw1-az1-p1 40:54:00:00:01:01 1342 10.0.1.3 24 10.0.1.1 2001::3/64 2001::1
> +
> +# AZ2 - Create one logical switch with one port
> +check m_as ovn-central-az2-1 ovn-nbctl ls-add sw1-az2
> +check m_as ovn-central-az2-1 ovn-nbctl lsp-add sw1-az2 sw1-az2-port1
> +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-addresses sw1-az2-port1 "40:54:00:00:02:01 10.0.2.3 2002::3"
> +
> +# AZ2 - Create a logical router and attach the logical switch
> +check m_as ovn-central-az2-1 ovn-nbctl lr-add lr2
> +check m_as ovn-central-az2-1 ovn-nbctl lrp-add lr2 lr2-sw1-az2 00:00:00:00:ff:02 10.0.2.1/24 2002::1/64
> +check m_as ovn-central-az2-1 ovn-nbctl lsp-add sw1-az2 sw1-az2-lr2
> +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-type sw1-az2-lr2 router
> +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-addresses sw1-az2-lr2 router
> +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-options sw1-az2-lr2 router-port=lr2-sw1-az2
> +
> +# AZ2 - Create the LRP, LSP and interconnect to the Transit Switch
> +check m_as ovn-central-az2-1 ovn-nbctl lrp-add lr2 lr2-ts-1 00:00:00:00:00:02 169.254.251.2/24 fe80:10::2/64
> +check m_as ovn-central-az2-1 ovn-nbctl lrp-set-gateway-chassis lr2-ts-1 ovn-gw-2
> +check m_as ovn-central-az2-1 ovn-nbctl lsp-add ts-1 lr2-lsp1 -- \
> +    lsp-set-addresses lr2-lsp1 router -- \
> +    lsp-set-type lr2-lsp1 router -- \
> +    lsp-set-options lr2-lsp1 router-port=lr2-ts-1
> +
> +m_as ovn-chassis-2 ip link del sw1-az2-p1-p
> +m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-az2-port1 sw1-az2-p1 40:54:00:00:02:01 1342 10.0.2.3 24 10.0.2.1 2002::3/64 2002::1
> +
> +# AZ3 - Create one logical switch with one port
> +check m_as ovn-central-az3-1 ovn-nbctl ls-add sw1-az3
> +check m_as ovn-central-az3-1 ovn-nbctl lsp-add sw1-az3 sw1-az3-port1
> +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-addresses sw1-az3-port1 "40:54:00:00:03:01 10.0.3.3 2003::3"
> +
> +# AZ3 - Create a logical router and attach the logical switch
> +check m_as ovn-central-az3-1 ovn-nbctl lr-add lr3
> +check m_as ovn-central-az3-1 ovn-nbctl lrp-add lr3 lr3-sw1-az3 00:00:00:00:ff:03 10.0.3.1/24 2003::1/64
> +check m_as ovn-central-az3-1 ovn-nbctl lsp-add sw1-az3 sw1-az3-lr3
> +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-type sw1-az3-lr3 router
> +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-addresses sw1-az3-lr3 router
> +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-options sw1-az3-lr3 router-port=lr3-sw1-az3
> +
> +# AZ3 - Create the LRP, LSP and interconnect to the Transit Switch
> +check m_as ovn-central-az3-1 ovn-nbctl lrp-add lr3 lr3-ts-1 00:00:00:00:00:03 169.254.251.3/24 fe80:10::3/64
> +check m_as ovn-central-az3-1 ovn-nbctl lrp-set-gateway-chassis lr3-ts-1 ovn-gw-3
> +check m_as ovn-central-az3-1 ovn-nbctl lsp-add ts-1 lr3-lsp1 -- \
> +    lsp-set-addresses lr3-lsp1 router -- \
> +    lsp-set-type lr3-lsp1 router -- \
> +    lsp-set-options lr3-lsp1 router-port=lr3-ts-1
> +
> +m_as ovn-chassis-1 ip link del sw1-az3-p1-p
> +m_as ovn-chassis-3 /data/create_fake_vm.sh sw1-az3-port1 sw1-az3-p1 40:54:00:00:03:01 1342 10.0.3.3 24 10.0.3.1 2003::3/64 2003::1
> +
> +# Test routes from lr2 and lr3 were learned to lr1
> +AT_CHECK([m_as ovn-central-az1-1 ovn-nbctl lr-route-list lr1 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.2.0/24 169.254.251.2
> +10.0.3.0/24 169.254.251.3
> +2002::/64 fe80:10::2
> +2003::/64 fe80:10::3
> +])
> +
> +# Test routes from lr1 and lr3 were learned to lr2
> +AT_CHECK([m_as ovn-central-az2-1 ovn-nbctl lr-route-list lr2 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.1.0/24 169.254.251.1
> +10.0.3.0/24 169.254.251.3
> +2001::/64 fe80:10::1
> +2003::/64 fe80:10::3
> +])
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.1.0/24 169.254.251.1
> +10.0.2.0/24 169.254.251.2
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> +# Ping IPv4 test Inter-AZ - AZ1 vs AZ2
> +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.2.3 | FORMAT_PING], \
> +[0], [dnl
> +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> +])
> +
> +# Ping IPv4 test Inter-AZ - AZ1 vs AZ3
> +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.3.3 | FORMAT_PING], \
> +[0], [dnl
> +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> +])
> +
> +# Ping IPv6 test Inter-AZ - AZ1 vs AZ2
> +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping6 -q -c 3 -i 0.3 -w 2 2002::3 | FORMAT_PING], \
> +[0], [dnl
> +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> +])
> +
> +# Ping IPv6 test Inter-AZ - AZ1 vs AZ3
> +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping6 -q -c 3 -i 0.3 -w 2 2003::3 | FORMAT_PING], \
> +[0], [dnl
> +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> +])
> +
> +# Filter advertised routes by LRP - AZ1
> +check m_as ovn-central-az1-1 ovn-nbctl --wait=sb set logical_router_port lr1-ts-1 options:ic-route-filter-adv=10.0.1.0/24
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.2.0/24 169.254.251.2
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> +# Filter advertised routes by LR - AZ2
> +check m_as ovn-central-az2-1 ovn-nbctl --wait=sb set logical_router lr2 options:ic-route-filter-adv=10.0.2.0/24
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> +# Remove route advertisement filters (LRP + LR)
> +check m_as ovn-central-az1-1 ovn-nbctl --wait=sb remove logical_router_port lr1-ts-1 options ic-route-filter-adv
> +check m_as ovn-central-az2-1 ovn-nbctl --wait=sb remove logical_router lr2 options ic-route-filter-adv
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.1.0/24 169.254.251.1
> +10.0.2.0/24 169.254.251.2
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> +# Filter learned routes by LRP - AZ3
> +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb set logical_router_port lr3-ts-1 options:ic-route-filter-learn=10.0.1.0/24
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.2.0/24 169.254.251.2
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> +# Remove route learn filters (LRP) AZ3
> +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb remove logical_router_port lr3-ts-1 options ic-route-filter-learn
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.1.0/24 169.254.251.1
> +10.0.2.0/24 169.254.251.2
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> + Filter learned routes by LR - AZ3
> +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb set logical_router lr3 options:ic-route-filter-learn=10.0.2.0/24
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.1.0/24 169.254.251.1
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> +# Remove route learn filters (LR) AZ3
> +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb remove logical_router lr3 options ic-route-filter-learn
> +
> +# Test routes from lr1 and lr2 were learned to lr3
> +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> +10.0.1.0/24 169.254.251.1
> +10.0.2.0/24 169.254.251.2
> +2001::/64 fe80:10::1
> +2002::/64 fe80:10::2
> +])
> +
> +AT_CLEANUP
> --
> 2.34.1
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Numan Siddique Dec. 20, 2024, 10:23 p.m. UTC | #2
On Fri, Dec 20, 2024 at 5:22 PM Numan Siddique <numans@ovn.org> wrote:
>
> On Wed, Nov 27, 2024 at 3:43 AM Paulo Guilherme da Silva
> <silva.pauloguilherme@gmail.com> wrote:
> >
> > From: Paulo Guilherme da Silva <silva.pauloguilherme@gmail.com>
> >
> > This commit adds the ability for ovn-ic to filter routes between VPCs.
> > In use cases where the user is using vpc-peering(route tag) handling
> > multiple points of redistribution, when we connect more than one TS in
> > the same Logical Router it is essential that we have control over which
> > routes will be filtered or advertised by transit switch.
> >
> > Signed-off-by: Paulo Guilherme da Silva <silva.pauloguilherme@gmail.com>
> > Co-authored-by: Roberto Bartzen Acosta <rbartzen@gmail.com>
>
> Thanks for the patch.
>
> Please see below for a few comments.
>
> Overall the patch LGTM.
>
> Numan
>
> > ---
> >  .../workflows/ovn-fake-multinode-tests.yml    |   2 +-
> >  ic/ovn-ic.c                                   |  71 ++++--
> >  ovn-nb.xml                                    |  44 ++++
> >  tests/multinode-macros.at                     |  81 +++++++
> >  tests/multinode.at                            | 223 ++++++++++++++++++
> >  5 files changed, 401 insertions(+), 20 deletions(-)
> >
> > diff --git a/.github/workflows/ovn-fake-multinode-tests.yml b/.github/workflows/ovn-fake-multinode-tests.yml
> > index bf966299d..42d99830f 100644
> > --- a/.github/workflows/ovn-fake-multinode-tests.yml
> > +++ b/.github/workflows/ovn-fake-multinode-tests.yml
> > @@ -149,7 +149,7 @@ jobs:
> >
> >      - name: Start basic cluster
> >        run: |
> > -        sudo -E CHASSIS_COUNT=4 GW_COUNT=4 ./ovn_cluster.sh start
> > +        sudo -E ENABLE_SSL=no CENTRAL_COUNT=4 CHASSIS_COUNT=4 GW_COUNT=4 ./ovn_cluster.sh start
>
> For the next version of this patch, can you please trigger a fake
> multinode test in your github branch and share the
> CI run results in the commit message ?
>
>
> >          sudo podman exec -it ovn-central-az1-1 ovn-nbctl show
> >          sudo podman exec -it ovn-central-az1-1 ovn-appctl -t ovn-northd version
> >          sudo podman exec -it ovn-chassis-1 ovn-appctl -t ovn-controller version
> > diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
> > index c95b556f8..907184c38 100644
> > --- a/ic/ovn-ic.c
> > +++ b/ic/ovn-ic.c
> > @@ -1030,21 +1030,45 @@ prefix_is_link_local(struct in6_addr *prefix, unsigned int plen)
> >  }
> >
> >  static bool
> > -prefix_is_deny_listed(const struct smap *nb_options,
> > -                      struct in6_addr *prefix,
> > -                      unsigned int plen)
> > +prefix_is_filtered(const struct smap *nb_options,
> > +                   struct in6_addr *prefix,
> > +                   unsigned int plen,
> > +                   const struct nbrec_logical_router *nb_lr,
> > +                   const struct nbrec_logical_router_port *ts_lrp,
> > +                   bool is_advertisement)
> >  {
> > +    struct ds filter_list = DS_EMPTY_INITIALIZER;
> > +    const char *filter_direction = is_advertisement ? "ic-route-filter-adv" :\
> > +        "ic-route-filter-learn";
> >      const char *denylist = smap_get(nb_options, "ic-route-denylist");
> >      if (!denylist || !denylist[0]) {
> >          denylist = smap_get(nb_options, "ic-route-blacklist");
> > -        if (!denylist || !denylist[0]) {
> > -            return false;
> > +    }
> > +    if (denylist) {
> > +        ds_put_format(&filter_list, "%s,", denylist);
> > +    }
> > +    if (ts_lrp) {
> > +        const char *lrp_route_filter = smap_get(&ts_lrp->options,
> > +                                         filter_direction);
>
> nit: Please fix the indentation.
>
> > +        if (lrp_route_filter) {
> > +            ds_put_format(&filter_list, "%s,", lrp_route_filter);
> >          }
> >      }
> > +    const char *lr_route_filter = smap_get(&nb_lr->options,
> > +                                           filter_direction);
>
> nit: Please fix the indentation.
>
> > +    if (lr_route_filter) {
> > +        ds_put_format(&filter_list, "%s,", lr_route_filter);
> > +    }
> > +
> > +    if (!filter_list.length) {
>
> I think you can use the function

Please ignore this comment.

Numan


> > +        ds_destroy(&filter_list);
> > +        return false;
> > +    }
> > +
> >      struct in6_addr bl_prefix;
> >      unsigned int bl_plen;
> >      char *cur, *next, *start;
> > -    next = start = xstrdup(denylist);
> > +    next = start = xstrdup(ds_cstr(&filter_list));
> >      bool matched = false;
> >      while ((cur = strsep(&next, ",")) && *cur) {
> >          if (!ip46_parse_cidr(cur, &bl_prefix, &bl_plen)) {
>
> If ip46_parse_cidr() fails, there is a below warning which needs to be updated
> appropriately.  With this patch,  the while loop now parses not just
> the denylist
> but a set of filters.
>
> VLOG_WARN_RL(&rl, "Bad format in nb_global options:"
> "ic-route-denylist: %s. CIDR expected.", cur);
>
> > @@ -1087,6 +1111,7 @@ prefix_is_deny_listed(const struct smap *nb_options,
> >          break;
> >      }
> >      free(start);
> > +    ds_destroy(&filter_list);
> >      return matched;
> >  }
> >
> > @@ -1094,7 +1119,9 @@ static bool
> >  route_need_advertise(const char *policy,
> >                       struct in6_addr *prefix,
> >                       unsigned int plen,
> > -                     const struct smap *nb_options)
> > +                     const struct smap *nb_options,
> > +                     const struct nbrec_logical_router *nb_lr,
> > +                     const struct nbrec_logical_router_port *ts_lrp)
> >  {
> >      if (!smap_get_bool(nb_options, "ic-route-adv", false)) {
> >          return false;
> > @@ -1113,7 +1140,7 @@ route_need_advertise(const char *policy,
> >          return false;
> >      }
> >
> > -    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
> > +    if (prefix_is_filtered(nb_options, prefix, plen, nb_lr, ts_lrp, true)) {
> >          return false;
> >      }
> >      return true;
> > @@ -1162,7 +1189,8 @@ add_static_to_routes_ad(
> >      const struct nbrec_logical_router *nb_lr,
> >      const struct lport_addresses *nexthop_addresses,
> >      const struct smap *nb_options,
> > -    const char *route_tag)
> > +    const char *route_tag,
> > +    const struct nbrec_logical_router_port *ts_lrp)
> >  {
> >      struct in6_addr prefix, nexthop;
> >      unsigned int plen;
> > @@ -1171,7 +1199,8 @@ add_static_to_routes_ad(
> >          return;
> >      }
> >
> > -    if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options)) {
> > +    if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options,
> > +                              nb_lr, ts_lrp)) {
> >          return;
> >      }
> >
> > @@ -1212,7 +1241,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
> >                           const struct lport_addresses *nexthop_addresses,
> >                           const struct smap *nb_options,
> >                           const struct nbrec_logical_router *nb_lr,
> > -                         const char *route_tag)
> > +                         const char *route_tag,
> > +                         const struct nbrec_logical_router_port *ts_lrp)
> >  {
> >      struct in6_addr prefix, nexthop;
> >      unsigned int plen;
> > @@ -1220,7 +1250,8 @@ add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
> >          return;
> >      }
> >
> > -    if (!route_need_advertise(NULL, &prefix, plen, nb_options)) {
> > +    if (!route_need_advertise(NULL, &prefix, plen, nb_options,
> > +                              nb_lr, ts_lrp)) {
> >          VLOG_DBG("Route ad: skip network %s of lrp %s.",
> >                   network, nb_lrp->name);
> >          return;
> > @@ -1274,7 +1305,8 @@ static bool
> >  route_need_learn(const struct nbrec_logical_router *lr,
> >                   const struct icsbrec_route *isb_route,
> >                   struct in6_addr *prefix, unsigned int plen,
> > -                 const struct smap *nb_options)
> > +                 const struct smap *nb_options,
> > +                 const struct nbrec_logical_router_port *ts_lrp)
> >  {
> >      if (!smap_get_bool(nb_options, "ic-route-learn", false)) {
> >          return false;
> > @@ -1289,7 +1321,7 @@ route_need_learn(const struct nbrec_logical_router *lr,
> >          return false;
> >      }
> >
> > -    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
> > +    if (prefix_is_filtered(nb_options, prefix, plen, lr, ts_lrp, false)) {
> >          return false;
> >      }
> >
> > @@ -1427,7 +1459,7 @@ sync_learned_routes(struct ic_context *ctx,
> >                  continue;
> >              }
> >              if (!route_need_learn(ic_lr->lr, isb_route, &prefix, plen,
> > -                                  &nb_global->options)) {
> > +                                  &nb_global->options, lrp)) {
> >                  continue;
> >              }
> >
> > @@ -1613,7 +1645,8 @@ build_ts_routes_to_adv(struct ic_context *ctx,
> >                         struct lport_addresses *ts_port_addrs,
> >                         const struct nbrec_nb_global *nb_global,
> >                         const char *ts_route_table,
> > -                       const char *route_tag)
> > +                       const char *route_tag,
> > +                       const struct nbrec_logical_router_port *ts_lrp)
> >  {
> >      const struct nbrec_logical_router *lr = ic_lr->lr;
> >
> > @@ -1636,7 +1669,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,
> >          } else if (!strcmp(ts_route_table, nb_route->route_table)) {
> >              /* It may be a route to be advertised */
> >              add_static_to_routes_ad(routes_ad, nb_route, lr, ts_port_addrs,
> > -                                    &nb_global->options, route_tag);
> > +                                    &nb_global->options, route_tag, ts_lrp);
> >          }
> >      }
> >
> > @@ -1648,7 +1681,7 @@ build_ts_routes_to_adv(struct ic_context *ctx,
> >                  add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp,
> >                                           ts_port_addrs,
> >                                           &nb_global->options,
> > -                                         lr, route_tag);
> > +                                         lr, route_tag, ts_lrp);
> >              }
> >          } else {
> >              /* The router port of the TS port is ignored. */
> > @@ -1712,7 +1745,7 @@ collect_lr_routes(struct ic_context *ctx,
> >              route_tag = "";
> >          }
> >          build_ts_routes_to_adv(ctx, ic_lr, routes_ad, &ts_port_addrs,
> > -                               nb_global, route_table, route_tag);
> > +                               nb_global, route_table, route_tag, lrp);
> >          destroy_lport_addresses(&ts_port_addrs);
> >      }
> >  }
> > diff --git a/ovn-nb.xml b/ovn-nb.xml
> > index 5114bbc2e..9fdc3e348 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -2946,6 +2946,28 @@ or
> >          option is not present the limit is not set and the zone limit is
> >          derived from OvS default datapath limit.
> >        </column>
> > +
> > +      <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
> > +          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-filter-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
> > +          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="Common Columns">
> > @@ -3705,6 +3727,28 @@ or
> >            learned by the <code>ovn-ic</code> daemon.
> >          </p>
> >        </column>
> > +      <column name="options" key="ic-route-filter-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-filter-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/multinode-macros.at b/tests/multinode-macros.at
> > index 698d2c625..3babf5242 100644
> > --- a/tests/multinode-macros.at
> > +++ b/tests/multinode-macros.at
> > @@ -71,6 +71,7 @@ m_central_as () {
> >  }
> >
> >  check_fake_multinode_setup() {
> > +    skip_fake_node_multi_az_setup
> >      check m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
> >      AT_CHECK([m_as ovn-chassis-1 ovn-appctl -t ovn-controller version], [0], [ignore])
> >      AT_CHECK([m_as ovn-chassis-2 ovn-appctl -t ovn-controller version], [0], [ignore])
> > @@ -78,6 +79,86 @@ check_fake_multinode_setup() {
> >      AT_CHECK([m_as ovn-gw-1 ovn-appctl -t ovn-controller version], [0], [ignore])
> >  }
> >
> > +# Based on Tiago Pires patch (multinode: Adding multinode ovn-ic test)
>
> I see that you have taken the code from this patch -
> https://patchwork.ozlabs.org/project/ovn/patch/20241022183342.105084-1-tiago.pires@luizalabs.com/
>
> It's worth checking with Tiago if he is fine with it.  Since that
> patch has some comments from Dumitru,  those need to be addressed.
>
> Instead of copying the code from that patch,  I'd suggest that you
> take over that patch if Tiago is fine with it, address the review
> comments and make yourself the co-author of it.
> Does that sound good ?
>
> @Tiago - Are you fine with this ?  Or do you plan to address the
> review comments from Dumitru and submit v5 ?
>
>
>
> > +skip_fake_node_multi_az_setup() {
> > +    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> > +    if [[ $? == 0 ]] ; then
> > +        AT_CHECK([exit 77])
> > +    fi
> > +}
> > +
> > +check_fake_node_multi_az_setup() {
> > +    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> > +    if [[ $? != 0 ]] ; then
> > +        AT_CHECK([exit 77])
> > +    fi
> > +
> > +    # Check if the fake multinode setup is using SSL, it will
> > +    # skip if it is enabled. The cleanup will break the setup,
> > +    # so it is recommended to use without SSL in order to
> > +    # test the OVN IC with fake multinode setup.
> > +    m_as ovn-chassis-1 ovs-vsctl list open | grep "ssl:"
> > +    if [[ $? == 0 ]] ; then
> > +        AT_CHECK([exit 77])
> > +    fi
> > +}
> > +
> > +check_fake_multinode_setup_by_az() {
> > +    check_fake_node_multi_az_setup
> > +
> > +    m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
> > +    m_as ovn-central-az2-1 ovn-nbctl --wait=sb sync
> > +    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> > +
> > +    for c in $1
> > +    do
> > +        m_as $c ovn-appctl -t ovn-controller version
> > +    done
> > +}
> > +
> > +cleanup_multinode_resources_by_az() {
> > +    check_fake_node_multi_az_setup
> > +    m_as ovn-central-az1-1 rm -f /etc/ovn/ovnnb_db.db
> > +    m_as ovn-central-az1-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> > +    m_as ovn-central-az2-1 rm -f /etc/ovn/ovnnb_db.db
> > +    m_as ovn-central-az2-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> > +    m_as ovn-central-az3-1 rm -f /etc/ovn/ovnnb_db.db
> > +    m_as ovn-central-az3-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> > +    check m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
> > +    check m_as ovn-central-az2-1 ovn-nbctl --wait=sb sync
> > +    check m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
> > +
> > +    for c in $1
> > +    do
> > +        m_as $c ovs-vsctl del-br br-int
> > +        m_as $c ip --all netns delete
> > +    done
> > +}
> > +
> > +configure_multinode_az() {
> > +    # Configure OVN IC by AZ
> > +    check m_as ovn-central-az1-1 ovn-nbctl set-connection ptcp:6641
> > +    check m_as ovn-central-az1-1 ovn-sbctl set-connection ptcp:6642
> > +    check m_as ovn-central-az1-1 ovn-nbctl set NB_Global . name=ovn-central-az1-1
> > +    check m_as ovn-central-az1-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
> > +                            options:ic-route-learn=true
> > +    check m_as ovn-central-az2-1 ovn-nbctl set-connection ptcp:6641
> > +    check m_as ovn-central-az2-1 ovn-sbctl set-connection ptcp:6642
> > +    check m_as ovn-central-az2-1 ovn-nbctl set NB_Global . name=ovn-central-az2-1
> > +    check m_as ovn-central-az2-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
> > +                            options:ic-route-learn=true
> > +    check m_as ovn-central-az3-1 ovn-nbctl set-connection ptcp:6641
> > +    check m_as ovn-central-az3-1 ovn-sbctl set-connection ptcp:6642
> > +    check m_as ovn-central-az3-1 ovn-nbctl set NB_Global . name=ovn-central-az3-1
> > +    check m_as ovn-central-az3-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
> > +                            options:ic-route-learn=true
> > +
> > +    # Configure OVN IC Gateway
> > +    check m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-is-interconn=true
> > +    check m_as ovn-gw-2 ovs-vsctl set open . external-ids:ovn-is-interconn=true
> > +    check m_as ovn-gw-3 ovs-vsctl set open . external-ids:ovn-is-interconn=true
> > +}
> > +
> >  cleanup_multinode_resources() {
> >      m_as ovn-central-az1-1 rm -f /etc/ovn/ovnnb_db.db
> >      m_as ovn-central-az1-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
> > diff --git a/tests/multinode.at b/tests/multinode.at
> > index a45dc55cc..b7bd38eef 100644
> > --- a/tests/multinode.at
> > +++ b/tests/multinode.at
> > @@ -2582,3 +2582,226 @@ Connected to 10.0.2.4 (10.0.2.4) port 8080
> >  fi
> >
> >  AT_CLEANUP
> > +=======
>
> I think there is no need for the above line - "======="
>
>
> Thanks
> Numan
>
> > +AT_SETUP([ovn multinode - ovn-ic - inter-AZ IPv4/IPv6])
> > +
> > +# Based on Tiago Pires patch (multinode: Adding multinode ovn-ic test)
> > +
> > +# Check that ovn-fake-multinode setup is up and running - requires additional nodes
> > +check_fake_multinode_setup_by_az 'ovn-chassis-1 ovn-chassis-2 ovn-chassis-3 ovn-gw-1 ovn-gw-2 ovn-gw-3'
> > +
> > +# Delete the multinode NB and OVS resources before starting the test.
> > +cleanup_multinode_resources_by_az 'ovn-chassis-1 ovn-chassis-2 ovn-chassis-3 ovn-gw-1 ovn-gw-2 ovn-gw-3'
> > +
> > +# Configure OVN IC by AZ
> > +configure_multinode_az
> > +
> > +# Test Inter-AZ routing
> > +
> > +# Create the Transit Switch
> > +m_as ovn-central-az1-1 ovn-ic-nbctl ts-add ts-1
> > +
> > +# AZ1 - Create one logical switch with one port
> > +check m_as ovn-central-az1-1 ovn-nbctl ls-add sw1-az1
> > +check m_as ovn-central-az1-1 ovn-nbctl lsp-add sw1-az1 sw1-az1-port1
> > +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-addresses sw1-az1-port1 "40:54:00:00:01:01 10.0.1.3 2001::3"
> > +
> > +# AZ1 - Create a logical router and attach the logical switch
> > +check m_as ovn-central-az1-1 ovn-nbctl lr-add lr1
> > +check m_as ovn-central-az1-1 ovn-nbctl lrp-add lr1 lr1-sw1-az1 00:00:00:00:ff:01 10.0.1.1/24 2001::1/64
> > +check m_as ovn-central-az1-1 ovn-nbctl lsp-add sw1-az1 sw1-az1-lr1
> > +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-type sw1-az1-lr1 router
> > +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-addresses sw1-az1-lr1 router
> > +check m_as ovn-central-az1-1 ovn-nbctl lsp-set-options sw1-az1-lr1 router-port=lr1-sw1-az1
> > +
> > +# AZ1 - Create the LRP, LSP and interconnect to the Transit Switch
> > +check m_as ovn-central-az1-1 ovn-nbctl lrp-add lr1 lr1-ts-1 00:00:00:00:00:01 169.254.251.1/24 fe80:10::1/64
> > +check m_as ovn-central-az1-1 ovn-nbctl lrp-set-gateway-chassis lr1-ts-1 ovn-gw-1
> > +check m_as ovn-central-az1-1 ovn-nbctl lsp-add ts-1 lr1-lsp1 -- \
> > +    lsp-set-addresses lr1-lsp1 router -- \
> > +    lsp-set-type lr1-lsp1 router -- \
> > +    lsp-set-options lr1-lsp1 router-port=lr1-ts-1
> > +
> > +m_as ovn-chassis-1 ip link del sw1-az1-p1-p
> > +m_as ovn-chassis-1 /data/create_fake_vm.sh sw1-az1-port1 sw1-az1-p1 40:54:00:00:01:01 1342 10.0.1.3 24 10.0.1.1 2001::3/64 2001::1
> > +
> > +# AZ2 - Create one logical switch with one port
> > +check m_as ovn-central-az2-1 ovn-nbctl ls-add sw1-az2
> > +check m_as ovn-central-az2-1 ovn-nbctl lsp-add sw1-az2 sw1-az2-port1
> > +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-addresses sw1-az2-port1 "40:54:00:00:02:01 10.0.2.3 2002::3"
> > +
> > +# AZ2 - Create a logical router and attach the logical switch
> > +check m_as ovn-central-az2-1 ovn-nbctl lr-add lr2
> > +check m_as ovn-central-az2-1 ovn-nbctl lrp-add lr2 lr2-sw1-az2 00:00:00:00:ff:02 10.0.2.1/24 2002::1/64
> > +check m_as ovn-central-az2-1 ovn-nbctl lsp-add sw1-az2 sw1-az2-lr2
> > +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-type sw1-az2-lr2 router
> > +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-addresses sw1-az2-lr2 router
> > +check m_as ovn-central-az2-1 ovn-nbctl lsp-set-options sw1-az2-lr2 router-port=lr2-sw1-az2
> > +
> > +# AZ2 - Create the LRP, LSP and interconnect to the Transit Switch
> > +check m_as ovn-central-az2-1 ovn-nbctl lrp-add lr2 lr2-ts-1 00:00:00:00:00:02 169.254.251.2/24 fe80:10::2/64
> > +check m_as ovn-central-az2-1 ovn-nbctl lrp-set-gateway-chassis lr2-ts-1 ovn-gw-2
> > +check m_as ovn-central-az2-1 ovn-nbctl lsp-add ts-1 lr2-lsp1 -- \
> > +    lsp-set-addresses lr2-lsp1 router -- \
> > +    lsp-set-type lr2-lsp1 router -- \
> > +    lsp-set-options lr2-lsp1 router-port=lr2-ts-1
> > +
> > +m_as ovn-chassis-2 ip link del sw1-az2-p1-p
> > +m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-az2-port1 sw1-az2-p1 40:54:00:00:02:01 1342 10.0.2.3 24 10.0.2.1 2002::3/64 2002::1
> > +
> > +# AZ3 - Create one logical switch with one port
> > +check m_as ovn-central-az3-1 ovn-nbctl ls-add sw1-az3
> > +check m_as ovn-central-az3-1 ovn-nbctl lsp-add sw1-az3 sw1-az3-port1
> > +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-addresses sw1-az3-port1 "40:54:00:00:03:01 10.0.3.3 2003::3"
> > +
> > +# AZ3 - Create a logical router and attach the logical switch
> > +check m_as ovn-central-az3-1 ovn-nbctl lr-add lr3
> > +check m_as ovn-central-az3-1 ovn-nbctl lrp-add lr3 lr3-sw1-az3 00:00:00:00:ff:03 10.0.3.1/24 2003::1/64
> > +check m_as ovn-central-az3-1 ovn-nbctl lsp-add sw1-az3 sw1-az3-lr3
> > +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-type sw1-az3-lr3 router
> > +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-addresses sw1-az3-lr3 router
> > +check m_as ovn-central-az3-1 ovn-nbctl lsp-set-options sw1-az3-lr3 router-port=lr3-sw1-az3
> > +
> > +# AZ3 - Create the LRP, LSP and interconnect to the Transit Switch
> > +check m_as ovn-central-az3-1 ovn-nbctl lrp-add lr3 lr3-ts-1 00:00:00:00:00:03 169.254.251.3/24 fe80:10::3/64
> > +check m_as ovn-central-az3-1 ovn-nbctl lrp-set-gateway-chassis lr3-ts-1 ovn-gw-3
> > +check m_as ovn-central-az3-1 ovn-nbctl lsp-add ts-1 lr3-lsp1 -- \
> > +    lsp-set-addresses lr3-lsp1 router -- \
> > +    lsp-set-type lr3-lsp1 router -- \
> > +    lsp-set-options lr3-lsp1 router-port=lr3-ts-1
> > +
> > +m_as ovn-chassis-1 ip link del sw1-az3-p1-p
> > +m_as ovn-chassis-3 /data/create_fake_vm.sh sw1-az3-port1 sw1-az3-p1 40:54:00:00:03:01 1342 10.0.3.3 24 10.0.3.1 2003::3/64 2003::1
> > +
> > +# Test routes from lr2 and lr3 were learned to lr1
> > +AT_CHECK([m_as ovn-central-az1-1 ovn-nbctl lr-route-list lr1 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.2.0/24 169.254.251.2
> > +10.0.3.0/24 169.254.251.3
> > +2002::/64 fe80:10::2
> > +2003::/64 fe80:10::3
> > +])
> > +
> > +# Test routes from lr1 and lr3 were learned to lr2
> > +AT_CHECK([m_as ovn-central-az2-1 ovn-nbctl lr-route-list lr2 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.1.0/24 169.254.251.1
> > +10.0.3.0/24 169.254.251.3
> > +2001::/64 fe80:10::1
> > +2003::/64 fe80:10::3
> > +])
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.1.0/24 169.254.251.1
> > +10.0.2.0/24 169.254.251.2
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > +# Ping IPv4 test Inter-AZ - AZ1 vs AZ2
> > +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.2.3 | FORMAT_PING], \
> > +[0], [dnl
> > +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> > +])
> > +
> > +# Ping IPv4 test Inter-AZ - AZ1 vs AZ3
> > +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.3.3 | FORMAT_PING], \
> > +[0], [dnl
> > +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> > +])
> > +
> > +# Ping IPv6 test Inter-AZ - AZ1 vs AZ2
> > +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping6 -q -c 3 -i 0.3 -w 2 2002::3 | FORMAT_PING], \
> > +[0], [dnl
> > +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> > +])
> > +
> > +# Ping IPv6 test Inter-AZ - AZ1 vs AZ3
> > +M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping6 -q -c 3 -i 0.3 -w 2 2003::3 | FORMAT_PING], \
> > +[0], [dnl
> > +3 packets transmitted, 3 received, 0% packet loss, time 0ms
> > +])
> > +
> > +# Filter advertised routes by LRP - AZ1
> > +check m_as ovn-central-az1-1 ovn-nbctl --wait=sb set logical_router_port lr1-ts-1 options:ic-route-filter-adv=10.0.1.0/24
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.2.0/24 169.254.251.2
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > +# Filter advertised routes by LR - AZ2
> > +check m_as ovn-central-az2-1 ovn-nbctl --wait=sb set logical_router lr2 options:ic-route-filter-adv=10.0.2.0/24
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > +# Remove route advertisement filters (LRP + LR)
> > +check m_as ovn-central-az1-1 ovn-nbctl --wait=sb remove logical_router_port lr1-ts-1 options ic-route-filter-adv
> > +check m_as ovn-central-az2-1 ovn-nbctl --wait=sb remove logical_router lr2 options ic-route-filter-adv
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.1.0/24 169.254.251.1
> > +10.0.2.0/24 169.254.251.2
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > +# Filter learned routes by LRP - AZ3
> > +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb set logical_router_port lr3-ts-1 options:ic-route-filter-learn=10.0.1.0/24
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.2.0/24 169.254.251.2
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > +# Remove route learn filters (LRP) AZ3
> > +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb remove logical_router_port lr3-ts-1 options ic-route-filter-learn
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.1.0/24 169.254.251.1
> > +10.0.2.0/24 169.254.251.2
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > + Filter learned routes by LR - AZ3
> > +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb set logical_router lr3 options:ic-route-filter-learn=10.0.2.0/24
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.1.0/24 169.254.251.1
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > +# Remove route learn filters (LR) AZ3
> > +check m_as ovn-central-az3-1 ovn-nbctl --wait=sb remove logical_router lr3 options ic-route-filter-learn
> > +
> > +# Test routes from lr1 and lr2 were learned to lr3
> > +AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
> > +             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
> > +10.0.1.0/24 169.254.251.1
> > +10.0.2.0/24 169.254.251.2
> > +2001::/64 fe80:10::1
> > +2002::/64 fe80:10::2
> > +])
> > +
> > +AT_CLEANUP
> > --
> > 2.34.1
> >
> > _______________________________________________
> > dev mailing list
> > dev@openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
diff mbox series

Patch

diff --git a/.github/workflows/ovn-fake-multinode-tests.yml b/.github/workflows/ovn-fake-multinode-tests.yml
index bf966299d..42d99830f 100644
--- a/.github/workflows/ovn-fake-multinode-tests.yml
+++ b/.github/workflows/ovn-fake-multinode-tests.yml
@@ -149,7 +149,7 @@  jobs:
 
     - name: Start basic cluster
       run: |
-        sudo -E CHASSIS_COUNT=4 GW_COUNT=4 ./ovn_cluster.sh start
+        sudo -E ENABLE_SSL=no CENTRAL_COUNT=4 CHASSIS_COUNT=4 GW_COUNT=4 ./ovn_cluster.sh start
         sudo podman exec -it ovn-central-az1-1 ovn-nbctl show
         sudo podman exec -it ovn-central-az1-1 ovn-appctl -t ovn-northd version
         sudo podman exec -it ovn-chassis-1 ovn-appctl -t ovn-controller version
diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
index c95b556f8..907184c38 100644
--- a/ic/ovn-ic.c
+++ b/ic/ovn-ic.c
@@ -1030,21 +1030,45 @@  prefix_is_link_local(struct in6_addr *prefix, unsigned int plen)
 }
 
 static bool
-prefix_is_deny_listed(const struct smap *nb_options,
-                      struct in6_addr *prefix,
-                      unsigned int plen)
+prefix_is_filtered(const struct smap *nb_options,
+                   struct in6_addr *prefix,
+                   unsigned int plen,
+                   const struct nbrec_logical_router *nb_lr,
+                   const struct nbrec_logical_router_port *ts_lrp,
+                   bool is_advertisement)
 {
+    struct ds filter_list = DS_EMPTY_INITIALIZER;
+    const char *filter_direction = is_advertisement ? "ic-route-filter-adv" :\
+        "ic-route-filter-learn";
     const char *denylist = smap_get(nb_options, "ic-route-denylist");
     if (!denylist || !denylist[0]) {
         denylist = smap_get(nb_options, "ic-route-blacklist");
-        if (!denylist || !denylist[0]) {
-            return false;
+    }
+    if (denylist) {
+        ds_put_format(&filter_list, "%s,", denylist);
+    }
+    if (ts_lrp) {
+        const char *lrp_route_filter = smap_get(&ts_lrp->options,
+                                         filter_direction);
+        if (lrp_route_filter) {
+            ds_put_format(&filter_list, "%s,", lrp_route_filter);
         }
     }
+    const char *lr_route_filter = smap_get(&nb_lr->options,
+                                           filter_direction);
+    if (lr_route_filter) {
+        ds_put_format(&filter_list, "%s,", lr_route_filter);
+    }
+
+    if (!filter_list.length) {
+        ds_destroy(&filter_list);
+        return false;
+    }
+
     struct in6_addr bl_prefix;
     unsigned int bl_plen;
     char *cur, *next, *start;
-    next = start = xstrdup(denylist);
+    next = start = xstrdup(ds_cstr(&filter_list));
     bool matched = false;
     while ((cur = strsep(&next, ",")) && *cur) {
         if (!ip46_parse_cidr(cur, &bl_prefix, &bl_plen)) {
@@ -1087,6 +1111,7 @@  prefix_is_deny_listed(const struct smap *nb_options,
         break;
     }
     free(start);
+    ds_destroy(&filter_list);
     return matched;
 }
 
@@ -1094,7 +1119,9 @@  static bool
 route_need_advertise(const char *policy,
                      struct in6_addr *prefix,
                      unsigned int plen,
-                     const struct smap *nb_options)
+                     const struct smap *nb_options,
+                     const struct nbrec_logical_router *nb_lr,
+                     const struct nbrec_logical_router_port *ts_lrp)
 {
     if (!smap_get_bool(nb_options, "ic-route-adv", false)) {
         return false;
@@ -1113,7 +1140,7 @@  route_need_advertise(const char *policy,
         return false;
     }
 
-    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
+    if (prefix_is_filtered(nb_options, prefix, plen, nb_lr, ts_lrp, true)) {
         return false;
     }
     return true;
@@ -1162,7 +1189,8 @@  add_static_to_routes_ad(
     const struct nbrec_logical_router *nb_lr,
     const struct lport_addresses *nexthop_addresses,
     const struct smap *nb_options,
-    const char *route_tag)
+    const char *route_tag,
+    const struct nbrec_logical_router_port *ts_lrp)
 {
     struct in6_addr prefix, nexthop;
     unsigned int plen;
@@ -1171,7 +1199,8 @@  add_static_to_routes_ad(
         return;
     }
 
-    if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options)) {
+    if (!route_need_advertise(nb_route->policy, &prefix, plen, nb_options,
+                              nb_lr, ts_lrp)) {
         return;
     }
 
@@ -1212,7 +1241,8 @@  add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
                          const struct lport_addresses *nexthop_addresses,
                          const struct smap *nb_options,
                          const struct nbrec_logical_router *nb_lr,
-                         const char *route_tag)
+                         const char *route_tag,
+                         const struct nbrec_logical_router_port *ts_lrp)
 {
     struct in6_addr prefix, nexthop;
     unsigned int plen;
@@ -1220,7 +1250,8 @@  add_network_to_routes_ad(struct hmap *routes_ad, const char *network,
         return;
     }
 
-    if (!route_need_advertise(NULL, &prefix, plen, nb_options)) {
+    if (!route_need_advertise(NULL, &prefix, plen, nb_options,
+                              nb_lr, ts_lrp)) {
         VLOG_DBG("Route ad: skip network %s of lrp %s.",
                  network, nb_lrp->name);
         return;
@@ -1274,7 +1305,8 @@  static bool
 route_need_learn(const struct nbrec_logical_router *lr,
                  const struct icsbrec_route *isb_route,
                  struct in6_addr *prefix, unsigned int plen,
-                 const struct smap *nb_options)
+                 const struct smap *nb_options,
+                 const struct nbrec_logical_router_port *ts_lrp)
 {
     if (!smap_get_bool(nb_options, "ic-route-learn", false)) {
         return false;
@@ -1289,7 +1321,7 @@  route_need_learn(const struct nbrec_logical_router *lr,
         return false;
     }
 
-    if (prefix_is_deny_listed(nb_options, prefix, plen)) {
+    if (prefix_is_filtered(nb_options, prefix, plen, lr, ts_lrp, false)) {
         return false;
     }
 
@@ -1427,7 +1459,7 @@  sync_learned_routes(struct ic_context *ctx,
                 continue;
             }
             if (!route_need_learn(ic_lr->lr, isb_route, &prefix, plen,
-                                  &nb_global->options)) {
+                                  &nb_global->options, lrp)) {
                 continue;
             }
 
@@ -1613,7 +1645,8 @@  build_ts_routes_to_adv(struct ic_context *ctx,
                        struct lport_addresses *ts_port_addrs,
                        const struct nbrec_nb_global *nb_global,
                        const char *ts_route_table,
-                       const char *route_tag)
+                       const char *route_tag,
+                       const struct nbrec_logical_router_port *ts_lrp)
 {
     const struct nbrec_logical_router *lr = ic_lr->lr;
 
@@ -1636,7 +1669,7 @@  build_ts_routes_to_adv(struct ic_context *ctx,
         } else if (!strcmp(ts_route_table, nb_route->route_table)) {
             /* It may be a route to be advertised */
             add_static_to_routes_ad(routes_ad, nb_route, lr, ts_port_addrs,
-                                    &nb_global->options, route_tag);
+                                    &nb_global->options, route_tag, ts_lrp);
         }
     }
 
@@ -1648,7 +1681,7 @@  build_ts_routes_to_adv(struct ic_context *ctx,
                 add_network_to_routes_ad(routes_ad, lrp->networks[j], lrp,
                                          ts_port_addrs,
                                          &nb_global->options,
-                                         lr, route_tag);
+                                         lr, route_tag, ts_lrp);
             }
         } else {
             /* The router port of the TS port is ignored. */
@@ -1712,7 +1745,7 @@  collect_lr_routes(struct ic_context *ctx,
             route_tag = "";
         }
         build_ts_routes_to_adv(ctx, ic_lr, routes_ad, &ts_port_addrs,
-                               nb_global, route_table, route_tag);
+                               nb_global, route_table, route_tag, lrp);
         destroy_lport_addresses(&ts_port_addrs);
     }
 }
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 5114bbc2e..9fdc3e348 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -2946,6 +2946,28 @@  or
         option is not present the limit is not set and the zone limit is
         derived from OvS default datapath limit.
       </column>
+
+      <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
+          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-filter-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
+          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="Common Columns">
@@ -3705,6 +3727,28 @@  or
           learned by the <code>ovn-ic</code> daemon.
         </p>
       </column>
+      <column name="options" key="ic-route-filter-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-filter-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/multinode-macros.at b/tests/multinode-macros.at
index 698d2c625..3babf5242 100644
--- a/tests/multinode-macros.at
+++ b/tests/multinode-macros.at
@@ -71,6 +71,7 @@  m_central_as () {
 }
 
 check_fake_multinode_setup() {
+    skip_fake_node_multi_az_setup
     check m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
     AT_CHECK([m_as ovn-chassis-1 ovn-appctl -t ovn-controller version], [0], [ignore])
     AT_CHECK([m_as ovn-chassis-2 ovn-appctl -t ovn-controller version], [0], [ignore])
@@ -78,6 +79,86 @@  check_fake_multinode_setup() {
     AT_CHECK([m_as ovn-gw-1 ovn-appctl -t ovn-controller version], [0], [ignore])
 }
 
+# Based on Tiago Pires patch (multinode: Adding multinode ovn-ic test)
+skip_fake_node_multi_az_setup() {
+    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
+    if [[ $? == 0 ]] ; then
+        AT_CHECK([exit 77])
+    fi
+}
+
+check_fake_node_multi_az_setup() {
+    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
+    if [[ $? != 0 ]] ; then
+        AT_CHECK([exit 77])
+    fi
+
+    # Check if the fake multinode setup is using SSL, it will
+    # skip if it is enabled. The cleanup will break the setup,
+    # so it is recommended to use without SSL in order to
+    # test the OVN IC with fake multinode setup.
+    m_as ovn-chassis-1 ovs-vsctl list open | grep "ssl:"
+    if [[ $? == 0 ]] ; then
+        AT_CHECK([exit 77])
+    fi
+}
+
+check_fake_multinode_setup_by_az() {
+    check_fake_node_multi_az_setup
+
+    m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
+    m_as ovn-central-az2-1 ovn-nbctl --wait=sb sync
+    m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
+
+    for c in $1
+    do
+        m_as $c ovn-appctl -t ovn-controller version
+    done
+}
+
+cleanup_multinode_resources_by_az() {
+    check_fake_node_multi_az_setup
+    m_as ovn-central-az1-1 rm -f /etc/ovn/ovnnb_db.db
+    m_as ovn-central-az1-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
+    m_as ovn-central-az2-1 rm -f /etc/ovn/ovnnb_db.db
+    m_as ovn-central-az2-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
+    m_as ovn-central-az3-1 rm -f /etc/ovn/ovnnb_db.db
+    m_as ovn-central-az3-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
+    check m_as ovn-central-az1-1 ovn-nbctl --wait=sb sync
+    check m_as ovn-central-az2-1 ovn-nbctl --wait=sb sync
+    check m_as ovn-central-az3-1 ovn-nbctl --wait=sb sync
+
+    for c in $1
+    do
+        m_as $c ovs-vsctl del-br br-int
+        m_as $c ip --all netns delete
+    done
+}
+
+configure_multinode_az() {
+    # Configure OVN IC by AZ
+    check m_as ovn-central-az1-1 ovn-nbctl set-connection ptcp:6641
+    check m_as ovn-central-az1-1 ovn-sbctl set-connection ptcp:6642
+    check m_as ovn-central-az1-1 ovn-nbctl set NB_Global . name=ovn-central-az1-1
+    check m_as ovn-central-az1-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
+                            options:ic-route-learn=true
+    check m_as ovn-central-az2-1 ovn-nbctl set-connection ptcp:6641
+    check m_as ovn-central-az2-1 ovn-sbctl set-connection ptcp:6642
+    check m_as ovn-central-az2-1 ovn-nbctl set NB_Global . name=ovn-central-az2-1
+    check m_as ovn-central-az2-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
+                            options:ic-route-learn=true
+    check m_as ovn-central-az3-1 ovn-nbctl set-connection ptcp:6641
+    check m_as ovn-central-az3-1 ovn-sbctl set-connection ptcp:6642
+    check m_as ovn-central-az3-1 ovn-nbctl set NB_Global . name=ovn-central-az3-1
+    check m_as ovn-central-az3-1 ovn-nbctl set NB_Global . options:ic-route-adv=true \
+                            options:ic-route-learn=true
+
+    # Configure OVN IC Gateway
+    check m_as ovn-gw-1 ovs-vsctl set open . external-ids:ovn-is-interconn=true
+    check m_as ovn-gw-2 ovs-vsctl set open . external-ids:ovn-is-interconn=true
+    check m_as ovn-gw-3 ovs-vsctl set open . external-ids:ovn-is-interconn=true
+}
+
 cleanup_multinode_resources() {
     m_as ovn-central-az1-1 rm -f /etc/ovn/ovnnb_db.db
     m_as ovn-central-az1-1 /usr/share/ovn/scripts/ovn-ctl restart_northd
diff --git a/tests/multinode.at b/tests/multinode.at
index a45dc55cc..b7bd38eef 100644
--- a/tests/multinode.at
+++ b/tests/multinode.at
@@ -2582,3 +2582,226 @@  Connected to 10.0.2.4 (10.0.2.4) port 8080
 fi
 
 AT_CLEANUP
+=======
+AT_SETUP([ovn multinode - ovn-ic - inter-AZ IPv4/IPv6])
+
+# Based on Tiago Pires patch (multinode: Adding multinode ovn-ic test)
+
+# Check that ovn-fake-multinode setup is up and running - requires additional nodes
+check_fake_multinode_setup_by_az 'ovn-chassis-1 ovn-chassis-2 ovn-chassis-3 ovn-gw-1 ovn-gw-2 ovn-gw-3'
+
+# Delete the multinode NB and OVS resources before starting the test.
+cleanup_multinode_resources_by_az 'ovn-chassis-1 ovn-chassis-2 ovn-chassis-3 ovn-gw-1 ovn-gw-2 ovn-gw-3'
+
+# Configure OVN IC by AZ
+configure_multinode_az
+
+# Test Inter-AZ routing
+
+# Create the Transit Switch
+m_as ovn-central-az1-1 ovn-ic-nbctl ts-add ts-1
+
+# AZ1 - Create one logical switch with one port
+check m_as ovn-central-az1-1 ovn-nbctl ls-add sw1-az1
+check m_as ovn-central-az1-1 ovn-nbctl lsp-add sw1-az1 sw1-az1-port1
+check m_as ovn-central-az1-1 ovn-nbctl lsp-set-addresses sw1-az1-port1 "40:54:00:00:01:01 10.0.1.3 2001::3"
+
+# AZ1 - Create a logical router and attach the logical switch
+check m_as ovn-central-az1-1 ovn-nbctl lr-add lr1
+check m_as ovn-central-az1-1 ovn-nbctl lrp-add lr1 lr1-sw1-az1 00:00:00:00:ff:01 10.0.1.1/24 2001::1/64
+check m_as ovn-central-az1-1 ovn-nbctl lsp-add sw1-az1 sw1-az1-lr1
+check m_as ovn-central-az1-1 ovn-nbctl lsp-set-type sw1-az1-lr1 router
+check m_as ovn-central-az1-1 ovn-nbctl lsp-set-addresses sw1-az1-lr1 router
+check m_as ovn-central-az1-1 ovn-nbctl lsp-set-options sw1-az1-lr1 router-port=lr1-sw1-az1
+
+# AZ1 - Create the LRP, LSP and interconnect to the Transit Switch
+check m_as ovn-central-az1-1 ovn-nbctl lrp-add lr1 lr1-ts-1 00:00:00:00:00:01 169.254.251.1/24 fe80:10::1/64
+check m_as ovn-central-az1-1 ovn-nbctl lrp-set-gateway-chassis lr1-ts-1 ovn-gw-1
+check m_as ovn-central-az1-1 ovn-nbctl lsp-add ts-1 lr1-lsp1 -- \
+    lsp-set-addresses lr1-lsp1 router -- \
+    lsp-set-type lr1-lsp1 router -- \
+    lsp-set-options lr1-lsp1 router-port=lr1-ts-1
+
+m_as ovn-chassis-1 ip link del sw1-az1-p1-p
+m_as ovn-chassis-1 /data/create_fake_vm.sh sw1-az1-port1 sw1-az1-p1 40:54:00:00:01:01 1342 10.0.1.3 24 10.0.1.1 2001::3/64 2001::1
+
+# AZ2 - Create one logical switch with one port
+check m_as ovn-central-az2-1 ovn-nbctl ls-add sw1-az2
+check m_as ovn-central-az2-1 ovn-nbctl lsp-add sw1-az2 sw1-az2-port1
+check m_as ovn-central-az2-1 ovn-nbctl lsp-set-addresses sw1-az2-port1 "40:54:00:00:02:01 10.0.2.3 2002::3"
+
+# AZ2 - Create a logical router and attach the logical switch
+check m_as ovn-central-az2-1 ovn-nbctl lr-add lr2
+check m_as ovn-central-az2-1 ovn-nbctl lrp-add lr2 lr2-sw1-az2 00:00:00:00:ff:02 10.0.2.1/24 2002::1/64
+check m_as ovn-central-az2-1 ovn-nbctl lsp-add sw1-az2 sw1-az2-lr2
+check m_as ovn-central-az2-1 ovn-nbctl lsp-set-type sw1-az2-lr2 router
+check m_as ovn-central-az2-1 ovn-nbctl lsp-set-addresses sw1-az2-lr2 router
+check m_as ovn-central-az2-1 ovn-nbctl lsp-set-options sw1-az2-lr2 router-port=lr2-sw1-az2
+
+# AZ2 - Create the LRP, LSP and interconnect to the Transit Switch
+check m_as ovn-central-az2-1 ovn-nbctl lrp-add lr2 lr2-ts-1 00:00:00:00:00:02 169.254.251.2/24 fe80:10::2/64
+check m_as ovn-central-az2-1 ovn-nbctl lrp-set-gateway-chassis lr2-ts-1 ovn-gw-2
+check m_as ovn-central-az2-1 ovn-nbctl lsp-add ts-1 lr2-lsp1 -- \
+    lsp-set-addresses lr2-lsp1 router -- \
+    lsp-set-type lr2-lsp1 router -- \
+    lsp-set-options lr2-lsp1 router-port=lr2-ts-1
+
+m_as ovn-chassis-2 ip link del sw1-az2-p1-p
+m_as ovn-chassis-2 /data/create_fake_vm.sh sw1-az2-port1 sw1-az2-p1 40:54:00:00:02:01 1342 10.0.2.3 24 10.0.2.1 2002::3/64 2002::1
+
+# AZ3 - Create one logical switch with one port
+check m_as ovn-central-az3-1 ovn-nbctl ls-add sw1-az3
+check m_as ovn-central-az3-1 ovn-nbctl lsp-add sw1-az3 sw1-az3-port1
+check m_as ovn-central-az3-1 ovn-nbctl lsp-set-addresses sw1-az3-port1 "40:54:00:00:03:01 10.0.3.3 2003::3"
+
+# AZ3 - Create a logical router and attach the logical switch
+check m_as ovn-central-az3-1 ovn-nbctl lr-add lr3
+check m_as ovn-central-az3-1 ovn-nbctl lrp-add lr3 lr3-sw1-az3 00:00:00:00:ff:03 10.0.3.1/24 2003::1/64
+check m_as ovn-central-az3-1 ovn-nbctl lsp-add sw1-az3 sw1-az3-lr3
+check m_as ovn-central-az3-1 ovn-nbctl lsp-set-type sw1-az3-lr3 router
+check m_as ovn-central-az3-1 ovn-nbctl lsp-set-addresses sw1-az3-lr3 router
+check m_as ovn-central-az3-1 ovn-nbctl lsp-set-options sw1-az3-lr3 router-port=lr3-sw1-az3
+
+# AZ3 - Create the LRP, LSP and interconnect to the Transit Switch
+check m_as ovn-central-az3-1 ovn-nbctl lrp-add lr3 lr3-ts-1 00:00:00:00:00:03 169.254.251.3/24 fe80:10::3/64
+check m_as ovn-central-az3-1 ovn-nbctl lrp-set-gateway-chassis lr3-ts-1 ovn-gw-3
+check m_as ovn-central-az3-1 ovn-nbctl lsp-add ts-1 lr3-lsp1 -- \
+    lsp-set-addresses lr3-lsp1 router -- \
+    lsp-set-type lr3-lsp1 router -- \
+    lsp-set-options lr3-lsp1 router-port=lr3-ts-1
+
+m_as ovn-chassis-1 ip link del sw1-az3-p1-p
+m_as ovn-chassis-3 /data/create_fake_vm.sh sw1-az3-port1 sw1-az3-p1 40:54:00:00:03:01 1342 10.0.3.3 24 10.0.3.1 2003::3/64 2003::1
+
+# Test routes from lr2 and lr3 were learned to lr1
+AT_CHECK([m_as ovn-central-az1-1 ovn-nbctl lr-route-list lr1 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.2.0/24 169.254.251.2
+10.0.3.0/24 169.254.251.3
+2002::/64 fe80:10::2
+2003::/64 fe80:10::3
+])
+
+# Test routes from lr1 and lr3 were learned to lr2
+AT_CHECK([m_as ovn-central-az2-1 ovn-nbctl lr-route-list lr2 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.1.0/24 169.254.251.1
+10.0.3.0/24 169.254.251.3
+2001::/64 fe80:10::1
+2003::/64 fe80:10::3
+])
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.1.0/24 169.254.251.1
+10.0.2.0/24 169.254.251.2
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+# Ping IPv4 test Inter-AZ - AZ1 vs AZ2
+M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.2.3 | FORMAT_PING], \
+[0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+# Ping IPv4 test Inter-AZ - AZ1 vs AZ3
+M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping -q -c 3 -i 0.3 -w 2 10.0.3.3 | FORMAT_PING], \
+[0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+# Ping IPv6 test Inter-AZ - AZ1 vs AZ2
+M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping6 -q -c 3 -i 0.3 -w 2 2002::3 | FORMAT_PING], \
+[0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+# Ping IPv6 test Inter-AZ - AZ1 vs AZ3
+M_NS_CHECK_EXEC([ovn-chassis-1], [sw1-az1-p1], [ping6 -q -c 3 -i 0.3 -w 2 2003::3 | FORMAT_PING], \
+[0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+# Filter advertised routes by LRP - AZ1
+check m_as ovn-central-az1-1 ovn-nbctl --wait=sb set logical_router_port lr1-ts-1 options:ic-route-filter-adv=10.0.1.0/24
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.2.0/24 169.254.251.2
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+# Filter advertised routes by LR - AZ2
+check m_as ovn-central-az2-1 ovn-nbctl --wait=sb set logical_router lr2 options:ic-route-filter-adv=10.0.2.0/24
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+# Remove route advertisement filters (LRP + LR)
+check m_as ovn-central-az1-1 ovn-nbctl --wait=sb remove logical_router_port lr1-ts-1 options ic-route-filter-adv
+check m_as ovn-central-az2-1 ovn-nbctl --wait=sb remove logical_router lr2 options ic-route-filter-adv
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.1.0/24 169.254.251.1
+10.0.2.0/24 169.254.251.2
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+# Filter learned routes by LRP - AZ3
+check m_as ovn-central-az3-1 ovn-nbctl --wait=sb set logical_router_port lr3-ts-1 options:ic-route-filter-learn=10.0.1.0/24
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.2.0/24 169.254.251.2
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+# Remove route learn filters (LRP) AZ3
+check m_as ovn-central-az3-1 ovn-nbctl --wait=sb remove logical_router_port lr3-ts-1 options ic-route-filter-learn
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.1.0/24 169.254.251.1
+10.0.2.0/24 169.254.251.2
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+ Filter learned routes by LR - AZ3
+check m_as ovn-central-az3-1 ovn-nbctl --wait=sb set logical_router lr3 options:ic-route-filter-learn=10.0.2.0/24
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.1.0/24 169.254.251.1
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+# Remove route learn filters (LR) AZ3
+check m_as ovn-central-az3-1 ovn-nbctl --wait=sb remove logical_router lr3 options ic-route-filter-learn
+
+# Test routes from lr1 and lr2 were learned to lr3
+AT_CHECK([m_as ovn-central-az3-1 ovn-nbctl lr-route-list lr3 |
+             grep learned | awk '{print $1, $2}' | sort], [0], [dnl
+10.0.1.0/24 169.254.251.1
+10.0.2.0/24 169.254.251.2
+2001::/64 fe80:10::1
+2002::/64 fe80:10::2
+])
+
+AT_CLEANUP