On Thu, Sep 11, 2025 at 09:09:53AM +0000, Indrajitt Valsaraj 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 <indrajitt.valsa...@nutanix.com> > > --- > v1: > - Address review comments from Mark > --- > NEWS | 3 + > ic/ovn-ic.c | 53 +++++++++---- > ovn-nb.xml | 66 +++++++++++++--- > tests/ovn-ic.at | 194 ++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 291 insertions(+), 25 deletions(-) > > diff --git a/NEWS b/NEWS > index 0cce1790d..44ec47b5e 100644 > --- a/NEWS > +++ b/NEWS > @@ -41,6 +41,9 @@ Post v25.03.0 > - Added support for running tests from the 'check-kernel' system test > target > under retis by setting OVS_TEST_WITH_RETIS=yes. See the 'Testing' > section > of the documentation for more details. > + - Added "ic-route-deny-adv" and "ic-route-deny-learn" options to > + the Logical_Router/Logical_Router_Port tables to allow users to > + deny filter advertised/learned IC routes. > > OVN v25.03.0 - 07 Mar 2025 > -------------------------- > diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c > index caffa6fe0..71174ae01 100644 > --- a/ic/ovn-ic.c > +++ b/ic/ovn-ic.c > @@ -1109,26 +1109,50 @@ prefix_is_filtered(struct in6_addr *prefix, > } > > static bool > -prefix_is_deny_listed(const struct smap *nb_options, > - struct in6_addr *prefix, > - unsigned int plen) > -{ > - const char *filter_name = "ic-route-denylist"; > - const char *denylist = smap_get(nb_options, filter_name); > - if (!denylist || !denylist[0]) { > - denylist = smap_get(nb_options, "ic-route-blacklist"); > - if (!denylist || !denylist[0]) { > - return false; > +prefix_is_deny_filtered(struct in6_addr *prefix, > + unsigned int plen, > + const struct smap *nb_options, > + const struct nbrec_logical_router *nb_lr, > + const struct nbrec_logical_router_port *ts_lrp, > + bool is_advertisement) > +{ > + struct ds deny_list = DS_EMPTY_INITIALIZER; > + const char *deny_key = is_advertisement ? "ic-route-deny-adv" : > + "ic-route-deny-learn"; > + > + if (ts_lrp) { > + const char *lrp_deny_filter = smap_get(&ts_lrp->options, deny_key); > + if (lrp_deny_filter) { > + ds_put_format(&deny_list, "%s,", lrp_deny_filter); > + } > + } > + > + if (nb_lr) { > + const char *lr_deny_filter = smap_get(&nb_lr->options, deny_key); > + if (lr_deny_filter) { > + ds_put_format(&deny_list, "%s,", lr_deny_filter); > + } > + } > + > + if (nb_options) { > + const char *global_deny = smap_get(nb_options, "ic-route-denylist"); > + if (!global_deny || !global_deny[0]) { > + global_deny = smap_get(nb_options, "ic-route-blacklist"); > + } > + if (global_deny && global_deny[0]) { > + ds_put_format(&deny_list, "%s,", global_deny); > } > } > > struct sset prefix_set = SSET_INITIALIZER(&prefix_set); > - sset_from_delimited_string(&prefix_set, denylist, ","); > + sset_from_delimited_string(&prefix_set, ds_cstr(&deny_list), ","); > > bool denied = false; > if (!sset_is_empty(&prefix_set)) { > - denied = find_prefix_in_set(prefix, plen, &prefix_set, filter_name); > + denied = find_prefix_in_set(prefix, plen, &prefix_set, deny_key); > } > + > + ds_destroy(&deny_list); > sset_destroy(&prefix_set); > return denied; > } > @@ -1158,7 +1182,8 @@ route_need_advertise(const char *policy, > return false; > } > > - if (prefix_is_deny_listed(nb_options, prefix, plen)) { > + if (prefix_is_deny_filtered(prefix, plen, nb_options, > + nb_lr, ts_lrp, true)) { > return false; > } > > @@ -1511,7 +1536,7 @@ route_need_learn(const struct nbrec_logical_router *lr, > return false; > } > > - if (prefix_is_deny_listed(nb_options, prefix, plen)) { > + if (prefix_is_deny_filtered(prefix, plen, nb_options, lr, ts_lrp, > false)) { > return false; > } > > diff --git a/ovn-nb.xml b/ovn-nb.xml > index 4a7581807..54f4fd2bd 100644 > --- a/ovn-nb.xml > +++ b/ovn-nb.xml > @@ -3231,7 +3231,7 @@ or > <column name="options" key="ic-route-filter-adv"> > <p> > This option expects list of CIDRs delimited by "," that's present > - in the Logical Router. A route will not be advertised if the > + in the Logical Router. A route will be advertised if the > route's prefix belongs to any of the CIDRs listed. > > This allows to filter CIDR prefixes in the process of advertising > @@ -3240,6 +3240,28 @@ or > </column> > > <column name="options" key="ic-route-filter-learn"> > + <p> > + This option expects list of CIDRs delimited by "," that's present > + in the Logical Router. A route will be learned if the > + route's prefix belongs to any of the CIDRs listed. > + > + This allows to filter CIDR prefixes in the process of learning > + routes in <code>ovn-ic</code> daemon. > + </p> > + </column> > + > + <column name="options" key="ic-route-deny-adv"> > + <p> > + This option expects list of CIDRs delimited by "," that's present > + in the Logical Router. A route will not be advertised if the > + route's prefix belongs to any of the CIDRs listed. > + > + This allows to filter CIDR prefixes in the process of advertising > + routes in <code>ovn-ic</code> daemon. > + </p> > + </column> > + > + <column name="options" key="ic-route-deny-learn"> > <p> > This option expects list of CIDRs delimited by "," that's present > in the Logical Router. A route will not be learned if the > @@ -4236,18 +4258,40 @@ or > This allows to filter CIDR prefixes in the process of advertising > routes in <code>ovn-ic</code> daemon. > </p> > - </column> > + </column> > > - <column name="options" key="ic-route-filter-learn"> > - <p> > - This option expects list of CIDRs delimited by "," that's present > - in the Logical Router Port. A route will be learned if the > - route's prefix belongs to any of the CIDRs listed. > + <column name="options" key="ic-route-filter-learn"> > + <p> > + This option expects list of CIDRs delimited by "," that's present > + in the Logical Router Port. A route will be learned if the > + route's prefix belongs to any of the CIDRs listed. > > - This allows to filter CIDR prefixes in the process of learning > - routes in <code>ovn-ic</code> daemon. > - </p> > - </column> > + This allows to filter CIDR prefixes in the process of learning > + routes in <code>ovn-ic</code> daemon. > + </p> > + </column> > + > + <column name="options" key="ic-route-deny-adv"> > + <p> > + This option expects list of CIDRs delimited by "," that's present > + in the Logical Router Port. A route will not be advertised if the > + route's prefix belongs to any of the CIDRs listed. > + > + This allows to filter CIDR prefixes in the process of advertising > + routes in <code>ovn-ic</code> daemon. > + </p> > + </column> > + > + <column name="options" key="ic-route-deny-learn"> > + <p> > + This option expects list of CIDRs delimited by "," that's present > in > + the Logical Router Port. A route will not be learned if the > + route's prefix belongs to any of the CIDRs listed. > + > + This allows to filter CIDR prefixes in the process of learning > + routes in <code>ovn-ic</code> daemon. > + </p> > + </column> > </group> > > <group title="Attachment"> > diff --git a/tests/ovn-ic.at b/tests/ovn-ic.at > index 49a409015..b866f9b8b 100644 > --- a/tests/ovn-ic.at > +++ b/tests/ovn-ic.at > @@ -3640,6 +3640,200 @@ OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl > lr-route-list lr11 | grep 2001 | > 2001:db12::/64 fe80:10::2 > ]) > > +OVN_CLEANUP_IC([az1], [az2]) > +AT_CLEANUP > +]) > + > +OVN_FOR_EACH_NORTHD([ > +AT_SETUP([ovn-ic -- prefix filter -- deny route adv]) > +ovn_init_ic_db > +ovn-ic-nbctl ts-add ts1 > +for i in 1 2; do > + ovn_start az$i > + ovn_as az$i > + check ovn-nbctl set nb_global . options:ic-route-learn=true > + check ovn-nbctl set nb_global . options:ic-route-adv=true > +done > + > +# Create routers and connect to transit switch > +for i in 1 2; do > + ovn_as az$i > + lr=lr1$i > + check ovn-nbctl lr-add $lr > + lrp=lrp-$lr-ts1 > + lsp=lsp-ts1-$lr > + check ovn-nbctl lrp-add $lr $lrp aa:aa:aa:aa:ab:0$i 169.254.101.$i/24 > fe80:10::$i/64 > + check ovn-nbctl lsp-add ts1 $lsp \ > + -- lsp-set-addresses $lsp router \ > + -- lsp-set-type $lsp router \ > + -- lsp-set-options $lsp router-port=$lrp > +done > + > +# Add directly connected routes to lr12 (first two test prefixes reused) > +ovn_as az2 check ovn-nbctl lrp-add lr12 lrp-lr12-1 aa:aa:aa:aa:cc:01 > "192.168.100.1/24" "2001:db12::1/64" > +ovn_as az2 check ovn-nbctl lrp-add lr12 lrp-lr12-2 aa:aa:aa:aa:cc:02 > "192.168.200.1/24" "2001:db22::1/64" > + > +# Sync IC DB > +check ovn-ic-nbctl --wait=sb sync > + > +# Validate lr11 learns both IPv4 and IPv6 routes from lr12 > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E > '192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.100.0/24 169.254.101.2 > +192.168.200.0/24 169.254.101.2 > +2001:db12::/64 fe80:10::2 > +2001:db22::/64 fe80:10::2 > +]) > + > +# Set deny-adv on lrp-lr12-ts1 for 192.168.100.0/24 > +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 > options:ic-route-deny-adv=192.168.100.0/24 > + > +# Only 192.168.200.0/24 should now be learned > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 > | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.200.0/24 169.254.101.2 > +]) > + > +# Add IPv6 deny prefix too > +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 > options:ic-route-deny-adv="192.168.100.0/24,2001:db12::/64" > + > +# Only 2001:db22::/64 should be learned now > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | > grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +2001:db22::/64 fe80:10::2 > +]) > + > +# Remove deny-adv and validate all are learned again > +ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options > ic-route-deny-adv > + > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep learned > | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.100.0/24 169.254.101.2 > +192.168.200.0/24 169.254.101.2 > +2001:db12::/64 fe80:10::2 > +2001:db22::/64 fe80:10::2 > +]) > + > +# --- Test ic-route-deny-learn --- > + > +# Set deny-learn on lrp-lr11-ts1 for 192.168.200.0/24 and 2001:db22::/64 > +ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 > options:ic-route-deny-learn="192.168.200.0/24,2001:db22::/64" > + > +# Now lr11 should only learn 192.168.100.0/24 and 2001:db12::/64 > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E > '192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.100.0/24 169.254.101.2 > +2001:db12::/64 fe80:10::2 > +]) > + > +# Remove deny-learn and confirm full route learning resumes > +ovn_as az1 check ovn-nbctl remove logical_router_port lrp-lr11-ts1 options > ic-route-deny-learn > + > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E > '192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.100.0/24 169.254.101.2 > +192.168.200.0/24 169.254.101.2 > +2001:db12::/64 fe80:10::2 > +2001:db22::/64 fe80:10::2 > +]) > + > +# --- Test setting deny options on logical router --- > + > +# Set deny-adv on lr12 for 192.168.100.0/24 > +ovn_as az2 check ovn-nbctl set logical_router lr12 > options:ic-route-deny-adv="192.168.100.0/24" > + > +# Sync again after router option is applied > +check ovn-ic-nbctl --wait=sb sync > + > +# Only 192.168.200.0/24 should now be learned > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 > | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.200.0/24 169.254.101.2 > +]) > + > +# Set deny-learn on lr11 for 2001:db22::/64 > +ovn_as az1 check ovn-nbctl set logical_router lr11 > options:ic-route-deny-learn="2001:db22::/64" > + > +# Only 2001:db12::/64 should now be learned > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 2001 | > grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +2001:db12::/64 fe80:10::2 > +]) > + > +# Clean up router-level options > +ovn_as az2 check ovn-nbctl remove logical_router lr12 options > ic-route-deny-adv > +ovn_as az1 check ovn-nbctl remove logical_router lr11 options > ic-route-deny-learn > + > +# Confirm all routes are back > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep learned > | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.100.0/24 169.254.101.2 > +192.168.200.0/24 169.254.101.2 > +2001:db12::/64 fe80:10::2 > +2001:db22::/64 fe80:10::2 > +]) > + > +# --- Test ic-route-denylist (global option) --- > + > +# Set global denylist to block 192.168.100.0/24 and 2001:db12::/64 > +ovn_as az2 check ovn-nbctl set nb_global . > options:ic-route-denylist="192.168.100.0/24,2001:db12::/64" > + > +# Now lr11 should only learn 192.168.200.0/24 and 2001:db22::/64 > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E > '192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.200.0/24 169.254.101.2 > +2001:db22::/64 fe80:10::2 > +]) > + > +# Remove global denylist > +ovn_as az2 check ovn-nbctl remove nb_global . options ic-route-denylist > + > +# Confirm all routes are learned again > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E > '192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.100.0/24 169.254.101.2 > +192.168.200.0/24 169.254.101.2 > +2001:db12::/64 fe80:10::2 > +2001:db22::/64 fe80:10::2 > +]) > + > +# --- Test combination of deny options --- > + > +# Set all deny filters > +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 > options:ic-route-deny-adv="192.168.100.0/24" > +ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 > options:ic-route-deny-learn="192.168.200.0/24" > +ovn_as az2 check ovn-nbctl set nb_global . > options:ic-route-denylist="2001:db12::/64" > + > +# Validate only 2001:db22::/64 is learned > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep -E > '192.168|2001' | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +2001:db22::/64 fe80:10::2 > +]) > + > +# Clean up for interaction tests > +ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options > ic-route-deny-adv > +ovn_as az1 check ovn-nbctl remove logical_router_port lrp-lr11-ts1 options > ic-route-deny-learn > +ovn_as az2 check ovn-nbctl remove nb_global . options ic-route-denylist > + > +# --- Test interactions between different filter options --- > + > +# Test ic-route-filter-adv vs ic-route-deny-adv precedence > +# Set both filter-adv (allow) and deny-adv (deny) for same CIDR - deny > should take precedence > +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 > options:ic-route-filter-adv="192.168.100.0/24,192.168.200.0/24" > +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 > options:ic-route-deny-adv="192.168.100.0/24" > + > +# Only 192.168.200.0/24 should be learned (192.168.100.0/24 denied despite > being in filter-adv) > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 > | grep learned | awk '{print $1, $2}' | sort], [0], [dnl > +192.168.200.0/24 169.254.101.2 > +]) > + > +# Clean up > +ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options > ic-route-filter-adv > +ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options > ic-route-deny-adv > + > +# Test cross-router interaction: filter-adv on lr12 vs deny-learn on lr11 > +# lr12 allows advertising 192.168.100.0/24, but lr11 denies learning it > +ovn_as az2 check ovn-nbctl set logical_router_port lrp-lr12-ts1 > options:ic-route-filter-adv="192.168.100.0/24" > +ovn_as az1 check ovn-nbctl set logical_router_port lrp-lr11-ts1 > options:ic-route-deny-learn="192.168.100.0/24" > + > +# 192.168.100.0/24 should not be learned (deny-learn takes precedence over > filter-adv) > +# No routes should be learned since only 192.168.100.0/24 is allowed to be > advertised but it's denied for learning > +OVS_WAIT_FOR_OUTPUT([ovn_as az1 ovn-nbctl lr-route-list lr11 | grep 192.168 > | grep learned | wc -l], [0], [0 > +]) > + > +# Clean up interaction tests > +ovn_as az2 check ovn-nbctl remove logical_router_port lrp-lr12-ts1 options > ic-route-filter-adv > +ovn_as az1 check ovn-nbctl remove logical_router_port lrp-lr11-ts1 options > ic-route-deny-learn > + > + > OVN_CLEANUP_IC([az1], [az2]) > AT_CLEANUP > ]) > -- > 2.39.3 > _______________________________________________ > dev mailing list > d...@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev >
Patch looks good to me Acked-by: Mairtin O'Loingsigh <moloi...@redhat.com> _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev