On 3 Mar 2026, at 18:07, 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]>
Thanks for the v4, Mike! Please find my review notes below. I think
something might have gone wrong in a find-and-replace.
//Eelco
> ---
> v2:
> - Allow the user to adjust the holdout timer
> - Corrected atomic barrier types
> - Display incomplete entries in tnl/neigh/show
> v3:
> - Renamed holdout to retrans
> - Adjusted functions of appctl commands
> - Updated comments and variable names
> v4:
> - Made testsuite grep more explicit
> ---
> NEWS | 3 +
> lib/tnl-neigh-cache.c | 162 +++++++++++++++++++++++++----
> 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 | 27 ++++-
> NEWS uses wrong prefix 'ovs/neigh/retrans_time', should be
> 'tnl/neigh/retrans_time'.
NEWS uses wrong prefix 'ovs/neigh/retrans_time', should be
'tnl/neigh/retrans_time'.
Also, code still uses 'retrans_ms' everywhere, you should rename to
'retrans_time'
throughout to align with kernel naming (command and functions).
> v3.7.0 - 16 Feb 2026
> diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c
> index bdff1debc..c6ed258e5 100644
> --- a/lib/tnl-neigh-cache.c
> +++ b/lib/tnl-neigh-cache.c
> @@ -47,6 +47,7 @@
>
> #define NEIGH_ENTRY_DEFAULT_IDLE_TIME_MS (15 * 60 * 1000)
> #define NEIGH_ENTRY_MAX_AGING_TIME_S 3600
> +#define NEIGH_ENTRY_LOOKUP_RETRANS_MS 1000
I was suggesting the following:
#define NEIGH_ENTRY_DEFAULT_IDLE_TIME_MS (15 * 60 * 1000)
#define NEIGH_ENTRY_MAX_AGING_TIME_S 3600
#define NEIGH_ENTRY_LOOKUP_RETRANS_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_retrans_ms;
See comment above; neigh_retrans_time;
>
> static uint32_t
> tnl_neigh_hash(const struct in6_addr *ip)
> @@ -85,6 +88,24 @@ tnl_neigh_get_aging(void)
> return aging;
> }
>
> +static uint32_t
> +tnl_neigh_get_retrans_ms(void)
tnl_neigh_get_retrans_time(void)
> +{
> + unsigned int retrans_ms;
> +
> + atomic_read_explicit(&neigh_retrans_ms, &retrans_ms,
> memory_order_acquire);
> + return retrans_ms;
> +}
> +
> +static bool
> +tnl_neigh_is_complete(struct tnl_neigh_entry *neigh)
> +{
> + bool complete;
> +
> + atomic_read_explicit(&neigh->complete, &complete, memory_order_acquire);
> + return complete;
> +}
> +
> static struct tnl_neigh_entry *
> tnl_neigh_lookup__(const char br_name[IFNAMSIZ], const struct in6_addr *dst)
> {
> @@ -98,27 +119,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_retrans_ms());
> + 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 insert_partial)
> {
> 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 (insert_partial && tnl_neigh_get_retrans_ms()) {
> + /* Insert a partial entry only if there is a retransmit timer set. */
> + tnl_neigh_set_partial(br_name, dst);
> }
> +
> return res;
> }
>
> @@ -142,26 +198,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
> @@ -308,12 +378,14 @@ tnl_neigh_cache_aging(struct unixctl_conn *conn, int
> argc,
> }
>
> if (!ovs_scan(argv[1], "%"SCNu32, &aging) ||
> - !aging || aging > NEIGH_ENTRY_MAX_AGING_TIME_S) {
> + !aging || aging > NEIGH_ENTRY_MAX_AGING_TIME_S ||
> + aging * 1000 < tnl_neigh_get_retrans_ms()) {
We prefer || on line stating. So maybe change this to:
if (!ovs_scan(argv[1], "%"SCNu32, &aging)
|| !aging || aging > NEIGH_ENTRY_MAX_AGING_TIME_S
|| aging * 1000 < tnl_neigh_get_retrans_ms()) {
However, maybe we should provide a more explicit message for the latter case,
as it might be hard to figure out why we’re erroring out.
> unixctl_command_reply_error(conn, "bad aging value");
> return;
> }
>
> aging *= 1000;
> +
Maybe move this above the if (...) statement so we don’t have to multiply twice?
> atomic_store_explicit(&neigh_aging, aging, memory_order_release);
> new_exp = time_msec() + aging;
>
> @@ -329,6 +401,48 @@ tnl_neigh_cache_aging(struct unixctl_conn *conn, int
> argc,
> unixctl_command_reply(conn, "OK");
> }
>
> +static void
> +tnl_neigh_cache_retrans_ms(struct unixctl_conn *conn, int argc,
tnl_neigh_cache_retrans_time
> + const char *argv[], void *aux OVS_UNUSED)
> +{
> + long long int new_exp, curr_exp;
> + struct tnl_neigh_entry *neigh;
> + uint32_t retrans_ms;
> +
> + if (argc == 1) {
> + struct ds ds = DS_EMPTY_INITIALIZER;
> + ds_put_format(&ds, "%"PRIu32, tnl_neigh_get_retrans_ms());
> + unixctl_command_reply(conn, ds_cstr(&ds));
> + ds_destroy(&ds);
> +
> + return;
> + }
> +
> + /* Zero retransmit value is acceptable. */
> + if (!ovs_scan(argv[1], "%"SCNu32, &retrans_ms) ||
|| on the next line.
> + retrans_ms > tnl_neigh_get_aging()) {
> + unixctl_command_reply_error(conn, "bad retrans_ms value");
bad retrans_time value
Same comment as earlie; should provide a more explicit message for the
latter case, as it might be hard to figure out why we’re erroring out.
> + return;
> + }
> +
> + atomic_store_explicit(&neigh_retrans_ms, retrans_ms,
> memory_order_release);
> + new_exp = time_msec() + retrans_ms;
> +
> + 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 +501,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, " %s INCOMPLETE",
> + neigh->br_name);
> + }
> if (tnl_neigh_expired(neigh)) {
> ds_put_format(&ds, " STALE");
> }
> @@ -404,6 +523,7 @@ void
> tnl_neigh_cache_init(void)
> {
> atomic_init(&neigh_aging, NEIGH_ENTRY_DEFAULT_IDLE_TIME_MS);
> + atomic_init(&neigh_retrans_ms, NEIGH_ENTRY_LOOKUP_RETRANS_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 +540,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/retrans_ms", "[MSECS]", 0, 1,
tnl/neigh/retrans_time
> + tnl_neigh_cache_retrans_ms, NULL);
> }
> diff --git a/lib/tnl-neigh-cache.h b/lib/tnl-neigh-cache.h
> index 877bca312..e16155b4d 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 insert_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..10585e484 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.
> +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.
> +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)
> @@ -360,6 +373,8 @@ AT_CHECK([cat p0.pcap.txt | grep
> 93aa55aa55000086dd6000000000203aff2001cafe | un
> ])
>
> dnl Set the aging time to 5 seconds
> +AT_CHECK([ovs-appctl tnl/neigh/retrans_ms 5000], [0], [OK
> +])
> AT_CHECK([ovs-appctl tnl/neigh/aging 5], [0], [OK
> ])
>
> @@ -373,6 +388,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 br0
> INCOMPLETE
> ])
>
> ovs-appctl time/warp 5000
> @@ -438,7 +454,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 br | grep -v INCOMPLETE | sort],
> [0], [dnl
See previous revision review, I think we should try to wrap at 80 chars when
changing test cases. For this specific one:
dnl Previous receive causes a flood that results in a lookup of 1.1.2.93.
AT_CHECK([ovs-appctl tnl/neigh/show | grep br | grep -v INCOMPLETE | sort],
[0], [dnl
2001:cafe::92 f8:bc:12:44:34:b6 br0
])
Same for all the other similar changes below.
> 2001:cafe::92 f8:bc:12:44:34:b6 br0
> ])
>
> @@ -577,8 +594,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..ff0045858 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.
> +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 br0
> INCOMPLETE
> +1.1.2.93 br0
> INCOMPLETE
> +])
> +
> +dnl Second trace should not send any ARP lookups.
> +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/retrans_ms 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,24 @@ ovs-appctl: ovs-vswitchd: server returned an error
> AT_CHECK([ovs-appctl tnl/neigh/aging 1], [0], [OK
> ])
>
> +dnl Retrans must be smaller than aging.
> +AT_CHECK([ovs-appctl tnl/neigh/retrans_ms 2000], [2], [], [dnl
> +bad retrans_ms 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/retrans_ms 5000], [0], [OK
> +])
> +
> +dnl Reducing aging below retrans_ms will return error.
> +AT_CHECK([ovs-appctl tnl/neigh/aging 4], [2], [], [dnl
> +bad aging value
> +ovs-appctl: ovs-vswitchd: server returned an error
> +])
> +
> dnl Set the aging time to 5 seconds
> AT_CHECK([ovs-appctl tnl/neigh/aging 5], [0], [OK
> ])
> @@ -296,6 +333,9 @@ dnl Read the current aging time
> AT_CHECK([ovs-appctl tnl/neigh/aging], [0], [5
> ])
>
> +AT_CHECK([ovs-appctl tnl/neigh/retrans_ms], [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 +364,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 br | grep -v INCOMPLETE], [0],
> [dnl
> 1.1.2.92 f8:bc:12:44:34:c8 br0
> ])
>
> @@ -334,7 +374,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 br | grep -v INCOMPLETE], [0],
> [dnl
> 1.1.2.92 f8:bc:12:44:34:c8 br0
> ])
>
> @@ -345,7 +385,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 br | grep -v INCOMPLETE], [0],
> [dnl
> 1.1.2.92 f8:bc:12:44:34:c8 br0
> ])
>
> @@ -355,7 +395,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 br | grep -v INCOMPLETE], [0],
> [dnl
> 1.1.2.92 f8:bc:12:44:34:b6 br0
> ])
>
> @@ -366,7 +406,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 br | grep -v INCOMPLETE], [0],
> [dnl
> 1.1.2.92 f8:bc:12:44:34:b6 br0
> ])
>
> @@ -376,7 +416,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 br | grep -v INCOMPLETE], [0],
> [dnl
> 1.1.2.92 f8:bc:12:44:34:c8 br0
> ])
>
> @@ -386,7 +426,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 br | grep -v INCOMPLETE], [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