On Fri, Aug 29, 2025 at 07:29:24AM +0200, Ales Musil wrote:
> On Thu, Aug 28, 2025 at 5:52 PM Felix Huettner via dev <
> [email protected]> wrote:
> 
> > When installing a new flow then its idle_age will start ticking from 0.
> > We previously treated this as the flow being used and bumped the
> > MAC_Binding
> > timestamp. However if the flow has just been freshly installed it was
> > never used and therefore should not be bumped.
> > This is especially important for chassis that add the flows newly
> > because they became part of the relevant datapath.
> >
> > In case of a large enough mac_binding_age_threshold and if the datapath
> > is added and removed across chassis faster than the
> > mac_binding_age_threshold this can actually lead to MAC_Binding that are
> > never removed even though they are inactive.
> >
> > We also need to fix the test "MAC binding aging - probing GW router
> > Dynamic Neigh" since it previously relied on the fact that a newly
> > created flow directly triggers an update. This pushed the time of the
> > first probe request sufficiently for the test to work. As we now no
> > longer do this we can at most wait for 'cooldown_period' as afterwards a
> > probe might be send immediately.
> >
> > Signed-off-by: Felix Huettner <[email protected]>
> > ---
> >
> 
> Hi Felix,
> 
> thank you for the fix. I would suggest slightly different approach
> that is simpler IMO and doesn't increase memory usage.
> See down below.
> 
> 
> >  controller/mac-cache.c |  7 +++--
> >  controller/mac-cache.h |  2 ++
> >  tests/ovn.at           | 66 ++++++++++++++++++++++++++++++++++++++++--
> >  3 files changed, 71 insertions(+), 4 deletions(-)
> >
> > diff --git a/controller/mac-cache.c b/controller/mac-cache.c
> > index fcf5fa7d4..173e39145 100644
> > --- a/controller/mac-cache.c
> > +++ b/controller/mac-cache.c
> > @@ -348,6 +348,7 @@ mac_binding_stats_process_flow_stats(struct vector
> > *stats_vec,
> >  {
> >      struct mac_cache_stats stats = (struct mac_cache_stats) {
> >          .idle_age_ms = ofp_stats->idle_age * 1000,
> > +        .has_ever_hit = ofp_stats->idle_age < ofp_stats->duration_sec,
> >
> 
> Instead of adding new bool we can simply do the following if at the
> start of the "*_stats_process_flow_stats()":
> 
>     if (ofp_stats->idle_age == ofp_stats->duration_sec) {
>         return;
>     }
> 
> WDYT?

Hi Ales,

that sounds good for me.
I'll send a v2.

Thanks,
Felix

> 
>          .data.mb = (struct mac_binding_data) {
> >              .cookie = ntohll(ofp_stats->cookie),
> >              /* The port_key must be zero to match
> > @@ -419,7 +420,7 @@ mac_binding_stats_run(
> >
> >          /* If "idle_age" is under threshold it means that the mac binding
> > is
> >           * used on this chassis. */
> > -        if (stats->idle_age_ms < threshold->value) {
> > +        if (stats->has_ever_hit && stats->idle_age_ms < threshold->value)
> > {
> >              if (since_updated_ms >= threshold->cooldown_period) {
> >                  mac_binding_update_log("Updating active", &mb->data, true,
> >                                         threshold, stats->idle_age_ms,
> > @@ -452,6 +453,7 @@ fdb_stats_process_flow_stats(struct vector *stats_vec,
> >  {
> >      struct mac_cache_stats stats = (struct mac_cache_stats) {
> >          .idle_age_ms = ofp_stats->idle_age * 1000,
> > +        .has_ever_hit = ofp_stats->idle_age < ofp_stats->duration_sec,
> >          .data.fdb = (struct fdb_data) {
> >              .port_key = ofp_stats->match.flow.regs[MFF_LOG_INPORT -
> > MFF_REG0],
> >              .dp_key = ntohll(ofp_stats->match.flow.metadata),
> > @@ -514,7 +516,7 @@ fdb_stats_run(struct rconn *swconn OVS_UNUSED,
> >
> >          /* If "idle_age" is under threshold it means that the fdb entry is
> >           * used on this chassis. */
> > -        if (stats->idle_age_ms < threshold->value) {
> > +        if (stats->has_ever_hit && stats->idle_age_ms < threshold->value)
> > {
> >              if (since_updated_ms >= threshold->cooldown_period) {
> >                  fdb_update_log("Updating active", &fdb->data, true,
> >                                 threshold, stats->idle_age_ms,
> > @@ -838,6 +840,7 @@ mac_binding_probe_stats_process_flow_stats(
> >  {
> >      struct mac_cache_stats stats = (struct mac_cache_stats) {
> >          .idle_age_ms = ofp_stats->idle_age * 1000,
> > +        .has_ever_hit = ofp_stats->idle_age < ofp_stats->duration_sec,
> >          .data.mb = (struct mac_binding_data) {
> >              .cookie = ntohll(ofp_stats->cookie),
> >              /* The port_key must be zero to match
> > diff --git a/controller/mac-cache.h b/controller/mac-cache.h
> > index d7b5b9cd5..fa462e82c 100644
> > --- a/controller/mac-cache.h
> > +++ b/controller/mac-cache.h
> > @@ -93,6 +93,8 @@ struct fdb {
> >
> >  struct mac_cache_stats {
> >      int64_t idle_age_ms;
> > +    bool has_ever_hit; /* Defines if the entry might have been hit at all,
> > +                        * independent of idle_age_ms. */
> >
> >      union {
> >          /* Common data to identify MAC binding. */
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index 292ca0dae..81fbfc629 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -36578,6 +36578,68 @@ OVN_CLEANUP([hv1])
> >  AT_CLEANUP
> >  ])
> >
> > +OVN_FOR_EACH_NORTHD([
> > +AT_SETUP([MAC binding aging - unused entries])
> > +ovn_start
> > +
> > +net_add n1
> > +sim_add hv1
> > +as hv1
> > +check ovs-vsctl add-br br-phys
> > +ovn_attach n1 br-phys 192.168.0.1
> > +ovn-appctl -t ovn-controller vlog/set mac_cache:file:dbg pinctrl:file:dbg
> > +
> > +check ovn-nbctl                                                     \
> > +    -- ls-add ls1                                                   \
> > +    -- lr-add lr                                                    \
> > +    -- set logical_router lr options:mac_binding_age_threshold=4    \
> > +    -- lrp-add lr lr-ls1 00:00:00:00:10:00 192.168.10.1/24          \
> > +    -- lsp-add ls1 ls1-lr                                           \
> > +    -- lsp-set-type ls1-lr router                                   \
> > +    -- lsp-set-addresses ls1-lr router                              \
> > +    -- lsp-set-options ls1-lr router-port=lr-ls1                    \
> > +    -- lsp-add ls1 vif1                                             \
> > +    -- lsp-set-addresses vif1 "00:00:00:00:10:10 192.168.10.10"
> > +
> > +check ovs-vsctl                                      \
> > +    -- add-port br-int vif1                          \
> > +    -- set interface vif1 external-ids:iface-id=vif1
> > +
> > +OVN_POPULATE_ARP
> > +wait_for_ports_up
> > +check ovn-nbctl --wait=hv sync
> > +
> > +dnl Wait for pinctrl thread to be connected.
> > +OVS_WAIT_UNTIL([grep pinctrl hv1/ovn-controller.log | grep -q connected])
> > +
> > +dnl Create the MAC_Binding directly in the database to ensure it is never
> > used.
> > +dnl The timestamp is set to now.
> > +dp=$(fetch_column Datapath_Binding _uuid external_ids:name=lr)
> > +now=$(date +%s)000
> > +check_uuid ovn-sbctl create MAC_Binding datapath=$dp logical_port=lr-ls1 \
> > +           ip=192.168.10.20 'mac="00:00:00:11:22:33"' timestamp=$now
> > +
> > +dnl Wait until the flow is installed locally
> > +OVS_WAIT_UNTIL([ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |
> > grep 192.168.10.20])
> > +
> > +dnl Wait long enough to give ovn-controller the chance to decide if the
> > entry
> > +dnl should be bumped or not.
> > +sleep 2
> > +
> > +dnl The entry should still be there and the timestamp should not have been
> > +dnl updated
> > +check_row_count mac_binding 1 ip="192.168.10.20"
> > +new_ts=$(fetch_column MAC_Binding timestamp ip="192.168.10.20")
> > +check test "$now" = "$new_ts"
> > +
> > +dnl After waiting until the age threshold the entry should be deleted
> > +sleep 3
> > +check_row_count mac_binding 0 ip="192.168.10.20"
> > +
> > +OVN_CLEANUP([hv1])
> > +AT_CLEANUP
> > +])
> > +
> >  OVN_FOR_EACH_NORTHD([
> >  AT_SETUP([MAC binding aging - probing])
> >  AT_SKIP_IF([test $HAVE_SCAPY = no])
> > @@ -36844,7 +36906,7 @@ OVS_WAIT_UNTIL([$(ovs-ofctl dump-flows br-int
> > table=OFTABLE_MAC_BINDING | \
> >  n_arp=$(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |awk
> > '/arp_spa=192.168.20.2/{print <http://192.168.20.2/%7Bprint>
> > substr($4,11,1)}')
> >  # Check GW router does not send any ARP requests in this case.
> >  OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> > table=OFTABLE_MAC_CACHE_USE | \
> > -                       awk '/nw_src=192.168.10.100/{print
> > <http://192.168.10.100/%7Bprint> substr($6,10,1)}') -ge $((aging_th/2))])
> > +                       awk '/nw_src=192.168.10.100/{print
> > <http://192.168.10.100/%7Bprint> substr($6,10,1)}') -ge
> > $((aging_th*3/16))])
> >  AT_CHECK([test $(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE
> > |awk '/arp_spa=192.168.20.2/{print <http://192.168.20.2/%7Bprint>
> > substr($4,11,1)}') -eq $n_arp])
> >
> >  send_imcp_echo_req hv1 public 00:00:00:00:10:00 00:00:00:00:10:1a
> > 192.168.20.2 192.168.10.100
> > @@ -36865,7 +36927,7 @@ check_row_count mac_binding 1
> > mac=\"00:00:00:00:30:00\" ip=\"fd12::2\"
> >
> >  n_ipv6=$(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE |awk
> > '/ipv6_src=fd12::2/{print substr($4,11,1)}')
> >  OVS_WAIT_UNTIL([test $(ovs-ofctl dump-flows br-int
> > table=OFTABLE_MAC_CACHE_USE | \
> > -                       awk '/ipv6_src=fd12::2/{print substr($6,10,1)}')
> > -ge $((aging_th/2))])
> > +                       awk '/ipv6_src=fd12::2/{print substr($6,10,1)}')
> > -ge $((aging_th*3/16))])
> >  # Check GW router does not send any NS requests in this case.
> >  AT_CHECK([test $(ovs-ofctl dump-flows br-int table=OFTABLE_MAC_CACHE_USE
> > |awk '/ipv6_src=fd12::2/{print substr($4,11,1)}') -eq $n_ipv6])
> >  send_icmp6_echo_req hv1 public 00:00:00:00:10:00 00:00:00:00:50:01
> > fd12::2 fd11::64
> >
> > base-commit: 0935bd0fa6afa24ce013c08a2796758cd26d196b
> > --
> > 2.43.0
> >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
> >
> Thanks,
> Ales
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to