On Thu, Feb 26, 2026 at 8:35 AM Eelco Chaudron <[email protected]> wrote:

>
>
> On 18 Feb 2026, at 22:37, Mike Pattrick via dev wrote:
>
> > Currently there is no rate limit on tunnel hardware address ARP/ND
> > lookups. Furthermote, there is no indication for how frequently action
> > translation composes these packets.
> >
> > This patch implements a limit of generating one packet per destination
> > per second and adds a counter for each time a lookup happens.
> >
> > Fixes: a36de779d739 ("openvswitch: Userspace tunneling.")
> > Reported-at: https://issues.redhat.com/browse/FDP-2986
> > Signed-off-by: Mike Pattrick <[email protected]>
> > ---
> > v2:
> >  - Allow the user to adjust the holdout timer
> >  - Corrected atomic barrier types
> >  - Display incomplete entries in tnl/neigh/show
> > ---
>
> Thanks, Mike, for sending out v2 of the patch. I’ve looked at it and have
> some comments below:
>
> //Eelco
>
> >  NEWS                               |   3 +
> >  lib/tnl-neigh-cache.c              | 169 +++++++++++++++++++++++++----
> >  lib/tnl-neigh-cache.h              |   2 +-
> >  ofproto/ofproto-dpif-xlate-cache.c |   2 +-
> >  ofproto/ofproto-dpif-xlate.c       |  12 +-
> >  tests/tunnel-push-pop-ipv6.at      |  25 ++++-
> >  tests/tunnel-push-pop.at           |  51 +++++++--
> >  7 files changed, 228 insertions(+), 36 deletions(-)
> >
> > diff --git a/NEWS b/NEWS
> > index d5642f985..a33b7bce0 100644
> > --- a/NEWS
> > +++ b/NEWS
> > @@ -1,5 +1,8 @@
> >  Post-v3.7.0
> >  --------------------
> > +   - Userspace datapath:
> > +     * ARP/ND lookups for native tunnel are now rate limited. The
> holdout
> > +       timer can be configured with 'ovs/neigh/holdout'.
>
> Should we try to align this with the kernel? ovs/neigh/retrans_time
>
> >  v3.7.0 - 16 Feb 2026
> > diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c
> > index bdff1debc..7c545cb51 100644
> > --- a/lib/tnl-neigh-cache.c
> > +++ b/lib/tnl-neigh-cache.c
> > @@ -45,8 +45,9 @@
> >  #include "openvswitch/vlog.h"
> >
> >
> > -#define NEIGH_ENTRY_DEFAULT_IDLE_TIME_MS  (15 * 60 * 1000)
> > -#define NEIGH_ENTRY_MAX_AGING_TIME_S  3600
> > +#define NEIGH_ENTRY_DEFAULT_IDLE_TIME_MS    (15 * 60 * 1000)
>
> I guess one space after _MS should be enough.
>
> > +#define NEIGH_ENTRY_MAX_AGING_TIME_S        3600
> > +#define NEIGH_ENTRY_LOOKUP_HOLDOUT_MS       1000
> >
> >  struct tnl_neigh_entry {
> >      struct cmap_node cmap_node;
> > @@ -54,11 +55,13 @@ struct tnl_neigh_entry {
> >      struct eth_addr mac;
> >      atomic_llong expires;       /* Expiration time in ms. */
> >      char br_name[IFNAMSIZ];
> > +    atomic_bool complete;
> >  };
> >
> >  static struct cmap table = CMAP_INITIALIZER;
> >  static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
> >  static atomic_uint32_t neigh_aging;
> > +static atomic_uint32_t neigh_holdout;
> >
> >  static uint32_t
> >  tnl_neigh_hash(const struct in6_addr *ip)
> > @@ -85,6 +88,25 @@ tnl_neigh_get_aging(void)
> >      return aging;
> >  }
> >
> > +static uint32_t
> > +tnl_neigh_get_holdout(void)
> > +{
> > +    unsigned int holdout;
> > +
> > +    atomic_read_explicit(&neigh_holdout, &holdout,
> memory_order_acquire);
> > +    return holdout;
> > +}
> > +
> > +static bool
> > +tnl_neigh_is_complete(struct tnl_neigh_entry *neigh)
> > +{
> > +    bool complete;
> > +
> > +    atomic_read_explicit(&neigh->complete, &complete,
> memory_order_acquire);
> > +
>
> Remove the extra new line here, as you do not have in the previous function
> > +    return complete;
> > +}
> > +
> >  static struct tnl_neigh_entry *
> >  tnl_neigh_lookup__(const char br_name[IFNAMSIZ], const struct in6_addr
> *dst)
> >  {
> > @@ -98,27 +120,62 @@ tnl_neigh_lookup__(const char br_name[IFNAMSIZ],
> const struct in6_addr *dst)
> >                  return NULL;
> >              }
> >
> > -            atomic_store_explicit(&neigh->expires, time_msec() +
> > -                                  tnl_neigh_get_aging(),
> > -                                  memory_order_release);
> > +            if (tnl_neigh_is_complete(neigh)) {
> > +                atomic_store_explicit(&neigh->expires,
> > +                                      time_msec() +
> tnl_neigh_get_aging(),
> > +                                      memory_order_release);
> > +            }
> > +
> >              return neigh;
> >          }
> >      }
> >      return NULL;
> >  }
> >
> > +static void
> > +tnl_neigh_set_partial(const char name[IFNAMSIZ], const struct in6_addr
> *dst)
> > +{
> > +    ovs_mutex_lock(&mutex);
> > +    struct tnl_neigh_entry *neigh = tnl_neigh_lookup__(name, dst);
> > +    if (neigh) {
> > +        /* Entry inserted before lock taken. */
> > +
> > +        ovs_mutex_unlock(&mutex);
> > +        return;
> > +    }
> > +    neigh = xmalloc(sizeof *neigh);
> > +
> > +    neigh->ip = *dst;
> > +    atomic_store_relaxed(&neigh->complete, false);
> > +    atomic_store_relaxed(&neigh->expires,
> > +                         time_msec() + tnl_neigh_get_holdout());
> > +    ovs_strlcpy(neigh->br_name, name, sizeof neigh->br_name);
> > +    cmap_insert(&table, &neigh->cmap_node, tnl_neigh_hash(&neigh->ip));
> > +
> > +    ovs_mutex_unlock(&mutex);
> > +    seq_change(tnl_conf_seq);
> > +}
> > +
> >  int
> >  tnl_neigh_lookup(const char br_name[IFNAMSIZ], const struct in6_addr
> *dst,
> > -                 struct eth_addr *mac)
> > +                 struct eth_addr *mac, bool allow_changes)
> >  {
> >      struct tnl_neigh_entry *neigh;
> >      int res = ENOENT;
> >
> >      neigh = tnl_neigh_lookup__(br_name, dst);
> >      if (neigh) {
> > -        *mac = neigh->mac;
> > -        res = 0;
> > +        if (tnl_neigh_is_complete(neigh)) {
> > +            *mac = neigh->mac;
> > +            res = 0;
> > +        } else {
> > +            res = EINPROGRESS;
> > +        }
> > +    } else if (allow_changes && tnl_neigh_get_holdout()) {
> > +        /* Insert a partial entry only if there is a holdout timer set.
> */
> > +        tnl_neigh_set_partial(br_name, dst);
> >      }
> > +
> >      return res;
> >  }
> >
> > @@ -142,26 +199,40 @@ tnl_neigh_set(const char name[IFNAMSIZ], const
> struct in6_addr *dst,
> >  {
> >      ovs_mutex_lock(&mutex);
> >      struct tnl_neigh_entry *neigh = tnl_neigh_lookup__(name, dst);
> > +    bool insert = true;
> > +
> >      if (neigh) {
> > -        if (eth_addr_equals(neigh->mac, mac)) {
> > -            atomic_store_relaxed(&neigh->expires, time_msec() +
> > -                                 tnl_neigh_get_aging());
> > +        if (!tnl_neigh_is_complete(neigh)) {
> > +            insert = false;
> > +        } else if (eth_addr_equals(neigh->mac, mac)) {
> > +            atomic_store_relaxed(&neigh->expires,
> > +                                 time_msec() + tnl_neigh_get_aging());
> >              ovs_mutex_unlock(&mutex);
> >              return;
> > +        } else {
> > +            tnl_neigh_delete(neigh);
> >          }
> > -        tnl_neigh_delete(neigh);
> >      }
> > -    seq_change(tnl_conf_seq);
> >
> > -    neigh = xmalloc(sizeof *neigh);
> > +    if (insert) {
> > +        neigh = xmalloc(sizeof *neigh);
> > +
> > +        neigh->ip = *dst;
> > +        ovs_strlcpy(neigh->br_name, name, sizeof neigh->br_name);
> > +    }
> >
> > -    neigh->ip = *dst;
> >      neigh->mac = mac;
> > -    atomic_store_relaxed(&neigh->expires, time_msec() +
> > -                         tnl_neigh_get_aging());
> > -    ovs_strlcpy(neigh->br_name, name, sizeof neigh->br_name);
> > -    cmap_insert(&table, &neigh->cmap_node, tnl_neigh_hash(&neigh->ip));
> > +    atomic_store_explicit(&neigh->expires,
> > +                          time_msec() + tnl_neigh_get_aging(),
> > +                          memory_order_release);
> > +    atomic_store_explicit(&neigh->complete, true, memory_order_release);
> > +
> > +    if (insert) {
> > +        cmap_insert(&table, &neigh->cmap_node,
> tnl_neigh_hash(&neigh->ip));
> > +    }
> > +
> >      ovs_mutex_unlock(&mutex);
> > +    seq_change(tnl_conf_seq);
> >  }
> >
> >  static void
> > @@ -317,6 +388,12 @@ tnl_neigh_cache_aging(struct unixctl_conn *conn,
> int argc,
> >      atomic_store_explicit(&neigh_aging, aging, memory_order_release);
> >      new_exp = time_msec() + aging;
> >
> > +    if (aging < tnl_neigh_get_holdout()) {
> > +        /* It isn't logical to for the holdout timer to be longer than
> the
>
> Guess the 'logical to for' needs 'to' to be removed.
>
> > +         * aging timer. */
> > +        atomic_store_relaxed(&neigh_holdout, aging);
>
> Should we really try to update a configuration here? Should it be done as
> part of the configuration check only?
> Do the check in tnl_neigh_cache_aging()? On top of this, should it be:
>
>   atomic_store_explicit(&neigh_holdout, aging, memory_order_release);
>
>
> > +    }
> > +
> >      CMAP_FOR_EACH (neigh, cmap_node, &table) {
> >          atomic_read_explicit(&neigh->expires, &curr_exp,
> >                               memory_order_acquire);
> > @@ -329,6 +406,48 @@ tnl_neigh_cache_aging(struct unixctl_conn *conn,
> int argc,
> >      unixctl_command_reply(conn, "OK");
> >  }
> >
> > +static void
> > +tnl_neigh_cache_holdout(struct unixctl_conn *conn, int argc,
> > +                        const char *argv[], void *aux OVS_UNUSED)
> > +{
> > +    long long int new_exp, curr_exp;
> > +    struct tnl_neigh_entry *neigh;
> > +    uint32_t holdout;
> > +
> > +    if (argc == 1) {
> > +        struct ds ds = DS_EMPTY_INITIALIZER;
> > +        ds_put_format(&ds, "%"PRIu32, tnl_neigh_get_holdout());
> > +        unixctl_command_reply(conn, ds_cstr(&ds));
> > +        ds_destroy(&ds);
> > +
> > +        return;
> > +    }
> > +
> > +    /* Zero holdout value is acceptable. */
> > +    if (!ovs_scan(argv[1], "%"SCNu32, &holdout) ||
> > +        holdout > tnl_neigh_get_aging()) {
> > +        unixctl_command_reply_error(conn, "bad holdout value");
> > +        return;
> > +    }
> > +
> > +    atomic_store_explicit(&neigh_holdout, holdout,
> memory_order_release);
> > +    new_exp = time_msec() + holdout;
> > +
> > +    CMAP_FOR_EACH (neigh, cmap_node, &table) {
> > +        if (tnl_neigh_is_complete(neigh)) {
> > +            continue;
> > +        }
> > +        atomic_read_explicit(&neigh->expires, &curr_exp,
> > +                             memory_order_acquire);
> > +        if (new_exp < curr_exp) {
> > +            atomic_store_explicit(&neigh->expires, new_exp,
> > +                                  memory_order_release);
> > +        }
> > +    }
> > +
> > +    unixctl_command_reply(conn, "OK");
> > +}
> > +
> >  static int
> >  lookup_any(const char *host_name, struct in6_addr *address)
> >  {
> > @@ -387,8 +506,13 @@ tnl_neigh_cache_show(struct unixctl_conn *conn, int
> argc OVS_UNUSED,
> >          need_ws = INET6_ADDRSTRLEN - (ds.length - start_len);
> >          ds_put_char_multiple(&ds, ' ', need_ws);
> >
> > -        ds_put_format(&ds, ETH_ADDR_FMT"   %s",
> > -                      ETH_ADDR_ARGS(neigh->mac), neigh->br_name);
> > +        if (tnl_neigh_is_complete(neigh)) {
> > +            ds_put_format(&ds, ETH_ADDR_FMT"   %s",
> > +                          ETH_ADDR_ARGS(neigh->mac), neigh->br_name);
> > +        } else {
> > +            ds_put_format(&ds, "00:00:00:00:00:00   %s INCOMPLETE",
>
> My preference is to show no MAC address at all, as technically all zeros
> is a valid MAC.
>
> > +                          neigh->br_name);
> > +        }
> >          if (tnl_neigh_expired(neigh)) {
> >              ds_put_format(&ds, " STALE");
> >          }
> > @@ -404,6 +528,7 @@ void
> >  tnl_neigh_cache_init(void)
> >  {
> >      atomic_init(&neigh_aging, NEIGH_ENTRY_DEFAULT_IDLE_TIME_MS);
> > +    atomic_init(&neigh_holdout, NEIGH_ENTRY_LOOKUP_HOLDOUT_MS);
> >      unixctl_command_register("tnl/arp/show", "", 0, 0,
> >                               tnl_neigh_cache_show, NULL);
> >      unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3,
> > @@ -420,4 +545,6 @@ tnl_neigh_cache_init(void)
> >                               tnl_neigh_cache_flush, NULL);
> >      unixctl_command_register("tnl/neigh/aging", "[SECS]", 0, 1,
> >                               tnl_neigh_cache_aging, NULL);
> > +    unixctl_command_register("tnl/neigh/holdout", "[MILLISECS]", 0, 1,
>
> Other commands use msecs, so maybe we should use it here too? I'm fine
> either way.
>
> > +                             tnl_neigh_cache_holdout, NULL);
> >  }
> > diff --git a/lib/tnl-neigh-cache.h b/lib/tnl-neigh-cache.h
> > index 877bca312..2aaa2168b 100644
> > --- a/lib/tnl-neigh-cache.h
> > +++ b/lib/tnl-neigh-cache.h
> > @@ -36,7 +36,7 @@ int tnl_neigh_snoop(const struct flow *flow, struct
> flow_wildcards *wc,
> >  void tnl_neigh_set(const char name[IFNAMSIZ], const struct in6_addr
> *dst,
> >                     const struct eth_addr mac);
> >  int tnl_neigh_lookup(const char dev_name[IFNAMSIZ], const struct
> in6_addr *dst,
> > -                     struct eth_addr *mac);
> > +                     struct eth_addr *mac, bool allow_changes);
>
> allow_changes still does not make it clear what this flag does. Even when
> set to false, it updates the timestamp. Maybe it should be
> allow_add_partial?
>
> >  void tnl_neigh_cache_init(void);
> >  void tnl_neigh_cache_run(void);
> >  void tnl_neigh_flush(const char dev_name[IFNAMSIZ]);
> > diff --git a/ofproto/ofproto-dpif-xlate-cache.c
> b/ofproto/ofproto-dpif-xlate-cache.c
> > index c6d935cf0..16cf812c9 100644
> > --- a/ofproto/ofproto-dpif-xlate-cache.c
> > +++ b/ofproto/ofproto-dpif-xlate-cache.c
> > @@ -152,7 +152,7 @@ xlate_push_stats_entry(struct xc_entry *entry,
> >      case XC_TNL_NEIGH:
> >          /* Lookup neighbor to avoid timeout. */
> >          tnl_neigh_lookup(entry->tnl_neigh_cache.br_name,
> > -                         &entry->tnl_neigh_cache.d_ipv6, &dmac);
> > +                         &entry->tnl_neigh_cache.d_ipv6, &dmac, false);
> >          break;
> >      case XC_TUNNEL_HEADER:
> >          if (entry->tunnel_hdr.operation == ADD) {
> > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> > index de82e2903..0b38dcf55 100644
> > --- a/ofproto/ofproto-dpif-xlate.c
> > +++ b/ofproto/ofproto-dpif-xlate.c
> > @@ -72,6 +72,7 @@
> >  COVERAGE_DEFINE(xlate_actions);
> >  COVERAGE_DEFINE(xlate_actions_oversize);
> >  COVERAGE_DEFINE(xlate_actions_too_many_output);
> > +COVERAGE_DEFINE(xlate_actions_neigh_sent);
> >
> >  VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate);
> >
> > @@ -3931,17 +3932,26 @@ native_tunnel_output(struct xlate_ctx *ctx,
> const struct xport *xport,
> >          s_ip = in6_addr_get_mapped_ipv4(&s_ip6);
> >      }
> >
> > -    err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac);
> > +    err = tnl_neigh_lookup(out_dev->xbridge->name, &d_ip6, &dmac, true);
> >      if (err) {
> >          struct in6_addr nh_s_ip6 = in6addr_any;
> >
> >          put_cloned_drop_action(ctx->xbridge->ofproto, ctx->odp_actions,
> >                                 XLATE_TUNNEL_NEIGH_CACHE_MISS,
> >                                 !is_last_action);
> > +        if (err == EINPROGRESS) {
> > +            xlate_report(ctx, OFT_DETAIL,
> > +                         "neighbor cache miss for %s on bridge %s, "
> > +                         "waiting on %s request",
> > +                         buf_dip6, out_dev->xbridge->name,
> > +                         d_ip ? "ARP" : "ND");
> > +            return err;
> > +        }
> >          xlate_report(ctx, OFT_DETAIL,
> >                       "neighbor cache miss for %s on bridge %s, "
> >                       "sending %s request",
> >                       buf_dip6, out_dev->xbridge->name, d_ip ? "ARP" :
> "ND");
> > +        COVERAGE_INC(xlate_actions_neigh_sent);
> >
> >          err = ovs_router_get_netdev_source_address(
> >              &d_ip6, netdev_get_name(out_dev->netdev), &nh_s_ip6);
> > diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/
> tunnel-push-pop-ipv6.at
> > index b11387345..2c885e1b5 100644
> > --- a/tests/tunnel-push-pop-ipv6.at
> > +++ b/tests/tunnel-push-pop-ipv6.at
> > @@ -344,7 +344,20 @@ AT_CHECK([ovs-ofctl add-flow br0 action=normal])
> >  dnl Check Neighbour discovery.
> >  AT_CHECK([ovs-vsctl -- set Interface p0 options:pcap=p0.pcap])
> >
> > -AT_CHECK([ovs-appctl netdev-dummy/receive int-br
> 'in_port(2),eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'])
> > +dnl First trace should send only two ND lookups, for each destination IP
>
> Comments should end with a dot.
>
> > +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "in_port(int-br),]dnl
> > +
> [eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),]dnl
> > +  [ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),]dnl
> > +  [icmp(type=0,code=0)"], [0], [stdout])
> > +AT_CHECK([grep -q "sending ND request" stdout], [0])
> > +
> > +dnl Second trace should not send any ND lookups
>
> Comments should end with a dot.
>
> > +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "in_port(int-br),]dnl
> > +
> [eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),]dnl
> > +  [ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),]dnl
> > +  [icmp(type=0,code=0)"], [0], [stdout])
> > +AT_CHECK([grep -q "waiting on ND request" stdout], [0])
> > +AT_CHECK([grep -qv "sending ND request" stdout], [0])
> >
> >  dnl Wait for the two Neighbor Solicitation packets to be sent.
> >  dnl Sometimes the system can be slow (e.g. under valgrind)
> > @@ -373,6 +386,7 @@ AT_CHECK([ovs-appctl tnl/neigh/set br0 2001:cafe::92
> aa:bb:cc:00:00:01], [0], [O
> >
> >  AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> >  2001:cafe::92                                 aa:bb:cc:00:00:01   br0
> > +2001:cafe::93                                 00:00:00:00:00:00   br0
> INCOMPLETE
> >  ])
> >
> >  ovs-appctl time/warp 5000
> > @@ -438,7 +452,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'in_port(200),eth(src=f8:bc:12:44:3
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br | sort], [0], [dnl
> > +dnl Previous receive causes a flood that results in a lookup of
> 1.1.2.93.
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92 | sort], [0], [dnl
>
> Wondering why we need this change? Is there more going on now?
>

Some of the flows in this test result in a flood which also triggers an arp
lookup resulting in an incomplete entry. However, that incomplete entry
isn't what the test is checking for, so I thought we should narrow what
we're grepping for in this case.

Cheers,
M


>
> >  2001:cafe::92                                 f8:bc:12:44:34:b6   br0
> >  ])
> >
> > @@ -577,8 +592,10 @@
> icmp,vlan_tci=0x0000,dl_src=be:b6:f4:e1:49:4a,dl_dst=fe:71:d8:83:72:4f,nw_src=30
> >  AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  5'], [0], [dnl
> >    port  5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=?
> >  ])
> > -AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'],
> [0], [dnl
> >
> -recirc_id(0),tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(+key)),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
> packets:0, bytes:0, used:never,
> actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=3,rule_cookie=0,controller_id=0,max_len=65535))
> > +AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)' |
> strip_recirc], [0], [dnl
> >
> +[recirc_id(<recirc>),tunnel(tun_id=0x7b,ipv6_src=2001:cafe::92,ipv6_dst=2001:cafe::88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(+key)),]dnl
> > +[in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
> packets:0, bytes:0, used:never, ]dnl
> >
> +[actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=<recirc>,rule_cookie=0,controller_id=0,max_len=65535))]
> >  ])
> >
> >  dnl Receive VXLAN with different MAC and verify that the neigh cache
> gets updated
> > diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
> > index f22a37570..4cd0970e6 100644
> > --- a/tests/tunnel-push-pop.at
> > +++ b/tests/tunnel-push-pop.at
> > @@ -256,7 +256,26 @@ AT_CHECK([ovs-appctl revalidator/wait])
> >  dnl Check ARP request
> >  AT_CHECK([ovs-vsctl -- set Interface p0 options:pcap=p0.pcap])
> >
> > -AT_CHECK([ovs-appctl netdev-dummy/receive int-br
> 'in_port(2),eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'])
> > +dnl First trace should send only two ARP lookups, for each destination
> IP
>
> Comments should end with a dot.
>
> > +AT_CHECK([ovs-appctl ofproto/trace ovs-dummy "in_port(int-br),]dnl
> > +
> [eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),]dnl
> > +  [ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),]dnl
> > +  [icmp(type=0,code=0)"], [0], [stdout])
> > +AT_CHECK([grep -q "sending ARP request" stdout], [0])
> > +
> > +dnl Check partial entry installed.
> > +AT_CHECK([ovs-appctl tnl/arp/show | grep INCOMPLETE | sort], [0], [dnl
> > +1.1.2.92                                      00:00:00:00:00:00   br0
> INCOMPLETE
> > +1.1.2.93                                      00:00:00:00:00:00   br0
> INCOMPLETE
> > +])
> > +
> > +dnl Second trace should not send any ARP lookups
>
> Comments should end with a dot.
>
> > +AT_CHECK([[ovs-appctl ofproto/trace ovs-dummy "in_port(int-br),]dnl
> > +
> [eth(src=aa:55:aa:55:00:00,dst=f8:bc:12:ff:ff:ff),eth_type(0x0800),]dnl
> > +  [ipv4(src=1.1.3.92,dst=1.1.3.88,proto=1,tos=0,ttl=64,frag=no),]dnl
> > +  [icmp(type=0,code=0)"]], [0], [stdout])
> > +AT_CHECK([grep -q "waiting on ARP request" stdout], [0])
> > +AT_CHECK([grep -qv "sending ARP request" stdout], [0])
> >
> >  dnl Wait for the two ARP requests to be sent. Sometimes the system
> >  dnl can be slow (e.g. under valgrind)
> > @@ -277,6 +296,9 @@ bad aging value
> >  ovs-appctl: ovs-vswitchd: server returned an error
> >  ])
> >
> > +AT_CHECK([ovs-appctl tnl/neigh/holdout 0], [0], [OK
> > +])
> > +
> >  AT_CHECK([ovs-appctl tnl/neigh/aging 3601], [2], [], [dnl
> >  bad aging value
> >  ovs-appctl: ovs-vswitchd: server returned an error
> > @@ -285,9 +307,18 @@ ovs-appctl: ovs-vswitchd: server returned an error
> >  AT_CHECK([ovs-appctl tnl/neigh/aging 1], [0], [OK
> >  ])
> >
> > +dnl Holdout must be smaller than aging.
> > +AT_CHECK([ovs-appctl tnl/neigh/holdout 2000], [2], [], [dnl
> > +bad holdout value
> > +ovs-appctl: ovs-vswitchd: server returned an error
> > +])
> > +
> >  AT_CHECK([ovs-appctl tnl/neigh/aging 3600], [0], [OK
> >  ])
> >
> > +AT_CHECK([ovs-appctl tnl/neigh/holdout 6000], [0], [OK
> > +])
> > +
> >  dnl Set the aging time to 5 seconds
> >  AT_CHECK([ovs-appctl tnl/neigh/aging 5], [0], [OK
> >  ])
> > @@ -296,6 +327,10 @@ dnl Read the current aging time
> >  AT_CHECK([ovs-appctl tnl/neigh/aging], [0], [5
> >  ])
> >
> > +dnl Reducing aging below holdout will also set holdout.
> > +AT_CHECK([ovs-appctl tnl/neigh/holdout], [0], [5000
> > +])
> > +
> >  dnl Add an entry
> >  AT_CHECK([ovs-appctl tnl/neigh/set br0 1.1.2.92 aa:bb:cc:00:00:01],
> [0], [OK
> >  ])
> > @@ -324,7 +359,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p0
> 'recirc_id(0),in_port(1),eth(src=f8
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92], [0], [dnl
> >  1.1.2.92                                      f8:bc:12:44:34:c8   br0
> >  ])
> >
> > @@ -334,7 +369,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p0
> 'recirc_id(0),in_port(1),eth(src=f8
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92], [0], [dnl
> >  1.1.2.92                                      f8:bc:12:44:34:c8   br0
> >  ])
> >
> > @@ -345,7 +380,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p0
> 'recirc_id(0),in_port(1),eth(src=f8
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92], [0], [dnl
> >  1.1.2.92                                      f8:bc:12:44:34:c8   br0
> >  ])
> >
> > @@ -355,7 +390,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p0
> 'recirc_id(0),in_port(1),eth(src=f8
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92], [0], [dnl
> >  1.1.2.92                                      f8:bc:12:44:34:b6   br0
> >  ])
> >
> > @@ -366,7 +401,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1
> 'recirc_id(0),in_port(200),eth(src=
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br | sort], [0], [dnl
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92], [0], [dnl
> >  1.1.2.92                                      f8:bc:12:44:34:b6   br0
> >  ])
> >
> > @@ -376,7 +411,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p0
> 'recirc_id(0),in_port(1),eth(src=f8
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br | sort], [0], [dnl
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92], [0], [dnl
> >  1.1.2.92                                      f8:bc:12:44:34:c8   br0
> >  ])
> >
> > @@ -386,7 +421,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p0
> 'recirc_id(0),in_port(1),eth(src=f8
> >  ovs-appctl time/warp 1000
> >  ovs-appctl time/warp 1000
> >
> > -AT_CHECK([ovs-appctl tnl/neigh/show | grep br | sort], [0], [dnl
> > +AT_CHECK([ovs-appctl tnl/neigh/show | grep 92], [0], [dnl
> >  1.1.2.92                                      f8:bc:12:44:34:b2   br0
> >  ])
> >
> > --
> > 2.53.0
> >
> > _______________________________________________
> > dev mailing list
> > [email protected]
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to