diff mbox series

[ovs-dev,2/4] Native tunnel: Add tnl/neigh/ageing command.

Message ID 163587314267.3737810.12870765406848931871.stgit@fed.void
State Superseded
Headers show
Series Native tunnel: Update neigh entries in tnl termination. | expand

Checks

Context Check Description
ovsrobot/apply-robot success apply and check: success
ovsrobot/github-robot-_Build_and_Test success github build: passed

Commit Message

Paolo Valerio Nov. 2, 2021, 5:12 p.m. UTC
with the command is now possible to change the ageing time of the
cache entries.

For the existing entries the ageing time is updated only if the
current expiration is greater than the new one. In any case, the next
refresh will set it to the new value.

This is intended mostly for debugging purpose.

Signed-off-by: Paolo Valerio <pvalerio@redhat.com>
---
 NEWS                            |    3 ++
 lib/tnl-neigh-cache.c           |   77 ++++++++++++++++++++++++++++++++++-----
 ofproto/ofproto-tnl-unixctl.man |    9 +++++
 tests/tunnel-push-pop-ipv6.at   |   30 +++++++++++++++
 tests/tunnel-push-pop.at        |   30 +++++++++++++++
 5 files changed, 140 insertions(+), 9 deletions(-)

Comments

Gaetan Rivet Nov. 3, 2021, 7:01 p.m. UTC | #1
On Tue, Nov 2, 2021, at 18:12, Paolo Valerio wrote:
> with the command is now possible to change the ageing time of the
> cache entries.
>
> For the existing entries the ageing time is updated only if the
> current expiration is greater than the new one. In any case, the next
> refresh will set it to the new value.
>
> This is intended mostly for debugging purpose.
>
> Signed-off-by: Paolo Valerio <pvalerio@redhat.com>
> ---
>  NEWS                            |    3 ++
>  lib/tnl-neigh-cache.c           |   77 ++++++++++++++++++++++++++++++++++-----
>  ofproto/ofproto-tnl-unixctl.man |    9 +++++
>  tests/tunnel-push-pop-ipv6.at   |   30 +++++++++++++++
>  tests/tunnel-push-pop.at        |   30 +++++++++++++++
>  5 files changed, 140 insertions(+), 9 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index 90f4b1590..148dd5d61 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -10,6 +10,9 @@ Post-v2.16.0
>         limiting behavior.
>       * Add hardware offload support for matching IPv4/IPv6 frag types
>         (experimental).
> +   - Native tunnel:
> +     * Added new ovs-appctl tnl/neigh/ageing to read/write the neigh ageing
> +       time.
> 
> 
>  v2.16.0 - 16 Aug 2021
> diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c
> index 2769e5c3d..8eacaccd8 100644
> --- a/lib/tnl-neigh-cache.c
> +++ b/lib/tnl-neigh-cache.c
> @@ -47,6 +47,7 @@
> 
>  /* In milliseconds */
>  #define NEIGH_ENTRY_DEFAULT_IDLE_TIME  (15 * 60 * 1000)
> +#define NEIGH_ENTRY_MAX_AGEING_TIME    (3600 * 1000)

Same remark, using _MS suffix would be nice.

> 
>  struct tnl_neigh_entry {
>      struct cmap_node cmap_node;
> @@ -58,6 +59,7 @@ struct tnl_neigh_entry {
> 
>  static struct cmap table = CMAP_INITIALIZER;
>  static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
> +static atomic_uint32_t neigh_ageing;
> 
>  static uint32_t
>  tnl_neigh_hash(const struct in6_addr *ip)
> @@ -75,6 +77,15 @@ tnl_neigh_expired(struct tnl_neigh_entry *neigh)
>      return expired <= time_msec();
>  }
> 
> +static uint32_t
> +tnl_neigh_get_ageing(void)
> +{
> +    unsigned int ageing;
> +
> +    atomic_read_relaxed(&neigh_ageing, &ageing);
> +    return ageing;
> +}
> +
>  static struct tnl_neigh_entry *
>  tnl_neigh_lookup__(const char br_name[IFNAMSIZ], const struct in6_addr 
> *dst)
>  {
> @@ -89,7 +100,7 @@ tnl_neigh_lookup__(const char br_name[IFNAMSIZ], 
> const struct in6_addr *dst)
>              }
> 
>              atomic_store_relaxed(&neigh->expires, time_msec() +
> -                                 NEIGH_ENTRY_DEFAULT_IDLE_TIME);
> +                                 tnl_neigh_get_ageing());
>              return neigh;
>          }
>      }
> @@ -134,7 +145,7 @@ tnl_neigh_set__(const char name[IFNAMSIZ], const 
> struct in6_addr *dst,
>      if (neigh) {
>          if (eth_addr_equals(neigh->mac, mac)) {
>              atomic_store_relaxed(&neigh->expires, time_msec() +
> -                                 NEIGH_ENTRY_DEFAULT_IDLE_TIME);
> +                                 tnl_neigh_get_ageing());
>              ovs_mutex_unlock(&mutex);
>              return;
>          }
> @@ -147,7 +158,7 @@ tnl_neigh_set__(const char name[IFNAMSIZ], const 
> struct in6_addr *dst,
>      neigh->ip = *dst;
>      neigh->mac = mac;
>      atomic_store_relaxed(&neigh->expires, time_msec() +
> -                         NEIGH_ENTRY_DEFAULT_IDLE_TIME);
> +                         tnl_neigh_get_ageing());
>      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);
> @@ -273,6 +284,43 @@ tnl_neigh_cache_flush(struct unixctl_conn *conn, 
> int argc OVS_UNUSED,
>      unixctl_command_reply(conn, "OK");
>  }
> 
> +static void
> +tnl_neigh_cache_ageing(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 ageing;
> +
> +    if (argc == 1) {
> +        struct ds ds = DS_EMPTY_INITIALIZER;
> +        ds_put_format(&ds, "%"PRIu32, tnl_neigh_get_ageing() / 1000);
> +        unixctl_command_reply(conn, ds_cstr(&ds));
> +        ds_destroy(&ds);
> +
> +        return;
> +    }
> +
> +    if (!ovs_scan(argv[1], "%"SCNu32, &ageing) ||
> +        !ageing || ageing > NEIGH_ENTRY_MAX_AGEING_TIME) {

ageing is provided in seconds, while NEIGH_ENTRY_MAX_AGEING_TIME is
in milliseconds right?

> +        unixctl_command_reply_error(conn, "bad ageing value");
> +        return;
> +    }
> +
> +    ageing *= 1000;
> +    atomic_store_relaxed(&neigh_ageing, ageing);

Release here with acquire in tnl_neigh_get_ageing() might be needed.

> +    new_exp = time_msec() + ageing;
> +
> +    CMAP_FOR_EACH (neigh, cmap_node, &table) {
> +        atomic_read_relaxed(&neigh->expires, &curr_exp);
> +        if (new_exp < curr_exp) {
> +            atomic_store_relaxed(&neigh->expires, new_exp);
> +        }

Potential re-ordering issue between read and write seems more acute here.
The explicit acquire / release ordering should probably be used.

> +    }
> +
> +    unixctl_command_reply(conn, "OK");
> +}
> +
>  static int
>  lookup_any(const char *host_name, struct in6_addr *address)
>  {
> @@ -347,10 +395,21 @@ tnl_neigh_cache_show(struct unixctl_conn *conn, 
> int argc OVS_UNUSED,
>  void
>  tnl_neigh_cache_init(void)
>  {
> -    unixctl_command_register("tnl/arp/show", "", 0, 0, 
> tnl_neigh_cache_show, NULL);
> -    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3, 
> tnl_neigh_cache_add, NULL);
> -    unixctl_command_register("tnl/arp/flush", "", 0, 0, 
> tnl_neigh_cache_flush, NULL);
> -    unixctl_command_register("tnl/neigh/show", "", 0, 0, 
> tnl_neigh_cache_show, NULL);
> -    unixctl_command_register("tnl/neigh/set", "BRIDGE IP MAC", 3, 3, 
> tnl_neigh_cache_add, NULL);
> -    unixctl_command_register("tnl/neigh/flush", "", 0, 0, 
> tnl_neigh_cache_flush, NULL);
> +    atomic_init(&neigh_ageing, NEIGH_ENTRY_DEFAULT_IDLE_TIME);
> +    unixctl_command_register("tnl/arp/show", "", 0, 0,
> +                             tnl_neigh_cache_show, NULL);
> +    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3,
> +                             tnl_neigh_cache_add, NULL);
> +    unixctl_command_register("tnl/arp/flush", "", 0, 0,
> +                             tnl_neigh_cache_flush, NULL);
> +    unixctl_command_register("tnl/arp/ageing", "[SECS]", 0, 1,
> +                             tnl_neigh_cache_ageing, NULL);
> +    unixctl_command_register("tnl/neigh/show", "", 0, 0,
> +                             tnl_neigh_cache_show, NULL);
> +    unixctl_command_register("tnl/neigh/set", "BRIDGE IP MAC", 3, 3,
> +                             tnl_neigh_cache_add, NULL);
> +    unixctl_command_register("tnl/neigh/flush", "", 0, 0,
> +                             tnl_neigh_cache_flush, NULL);
> +    unixctl_command_register("tnl/neigh/ageing", "[SECS]", 0, 1,
> +                             tnl_neigh_cache_ageing, NULL);
>  }
> diff --git a/ofproto/ofproto-tnl-unixctl.man 
> b/ofproto/ofproto-tnl-unixctl.man
> index c70cca539..5c2ad4843 100644
> --- a/ofproto/ofproto-tnl-unixctl.man
> +++ b/ofproto/ofproto-tnl-unixctl.man
> @@ -27,6 +27,15 @@ to \fImac\fR.
>  .IP "\fBtnl/arp/flush\fR"
>  Flush ARP table.
>  .
> +.IP "\fBtnl/neigh/ageing [\fIseconds\fB]\fR"
> +.IP "\fBtnl/arp/ageing [\fIseconds\fB]\fR"
> +Changes the ageing time. The accepted values of \fIseconds\fR are
> +between 1 and 3600. The new entries will get the value as specified in
> +\fIseconds\fR. For the existing entries, the ageing time is updated
> +only if the current expiration is greater than \fIseconds\fR.
> +.IP
> +If used without arguments, it prints the current ageing value.
> +.
>  .IP "\fBtnl/egress_port_range [num1] [num2]\fR"
>  Set range for UDP source port used for UDP based Tunnels. For
>  example VxLAN. If case of zero arguments this command prints
> diff --git a/tests/tunnel-push-pop-ipv6.at 
> b/tests/tunnel-push-pop-ipv6.at
> index 59723e63b..766a4bcf8 100644
> --- a/tests/tunnel-push-pop-ipv6.at
> +++ b/tests/tunnel-push-pop-ipv6.at
> @@ -255,6 +255,36 @@ AT_CHECK([cat p0.pcap.txt | grep 
> 93aa55aa55000086dd6000000000203aff2001cafe | un
>  
> 3333ff000093aa55aa55000086dd6000000000203aff2001cafe000000000000000000000088ff0200000000000000000001ff00009387004d46000000002001cafe0000000000000000000000930101aa55aa550000
>  ])
> 
> +dnl Set the ageing time to 5 seconds
> +AT_CHECK([ovs-appctl tnl/neigh/ageing 5], [0], [OK
> +])
> +
> +dnl Read the current ageing time
> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [5
> +])
> +
> +dnl Add an entry
> +AT_CHECK([ovs-appctl tnl/neigh/set br0 2001:cafe::92 
> aa:bb:cc:00:00:01], [0], [OK
> +])
> +
> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> +2001:cafe::92                                 aa:bb:cc:00:00:01   br0
> +])
> +
> +ovs-appctl time/warp 5000
> +
> +dnl Check the entry has been removed
> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> +])
> +
> +dnl Restore the ageing time to 900s (default)
> +AT_CHECK([ovs-appctl tnl/neigh/ageing 900], [0], [OK
> +])
> +
> +dnl Read the current ageing time
> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [900
> +])
> +
>  dnl Check ARP Snoop
>  AT_CHECK([ovs-appctl netdev-dummy/receive p0 
> 'in_port(1),eth(src=f8:bc:12:44:34:c8,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:c8)'])
> 
> diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
> index 12fc1ef91..385d14ab3 100644
> --- a/tests/tunnel-push-pop.at
> +++ b/tests/tunnel-push-pop.at
> @@ -270,6 +270,36 @@ AT_CHECK([cat p0.pcap.txt | grep 101025d | uniq], 
> [0], [dnl
>  
> ffffffffffffaa55aa55000008060001080006040001aa55aa550000010102580000000000000101025d
>  ])
> 
> +dnl Set the ageing time to 5 seconds
> +AT_CHECK([ovs-appctl tnl/neigh/ageing 5], [0], [OK
> +])
> +
> +dnl Read the current ageing time
> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [5
> +])
> +
> +dnl Add an entry
> +AT_CHECK([ovs-appctl tnl/neigh/set br0 1.1.2.92 aa:bb:cc:00:00:01], 
> [0], [OK
> +])
> +
> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> +1.1.2.92                                      aa:bb:cc:00:00:01   br0
> +])
> +
> +ovs-appctl time/warp 5000
> +
> +dnl Check the entry has been removed
> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
> +])
> +
> +dnl Restore the ageing time to 900s (default)
> +AT_CHECK([ovs-appctl tnl/neigh/ageing 900], [0], [OK
> +])
> +
> +dnl Read the current ageing time
> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [900
> +])
> +
>  dnl Check ARP Snoop
>  AT_CHECK([ovs-appctl netdev-dummy/receive p0 
> 'recirc_id(0),in_port(1),eth(src=f8:bc:12:44:34:c8,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:c8,tha=00:00:00:00:00:00)'])
> 
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
Paolo Valerio Nov. 8, 2021, 7:30 p.m. UTC | #2
Gaëtan Rivet <grive@u256.net> writes:

> On Tue, Nov 2, 2021, at 18:12, Paolo Valerio wrote:
>> with the command is now possible to change the ageing time of the
>> cache entries.
>>
>> For the existing entries the ageing time is updated only if the
>> current expiration is greater than the new one. In any case, the next
>> refresh will set it to the new value.
>>
>> This is intended mostly for debugging purpose.
>>
>> Signed-off-by: Paolo Valerio <pvalerio@redhat.com>
>> ---
>>  NEWS                            |    3 ++
>>  lib/tnl-neigh-cache.c           |   77 ++++++++++++++++++++++++++++++++++-----
>>  ofproto/ofproto-tnl-unixctl.man |    9 +++++
>>  tests/tunnel-push-pop-ipv6.at   |   30 +++++++++++++++
>>  tests/tunnel-push-pop.at        |   30 +++++++++++++++
>>  5 files changed, 140 insertions(+), 9 deletions(-)
>>
>> diff --git a/NEWS b/NEWS
>> index 90f4b1590..148dd5d61 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -10,6 +10,9 @@ Post-v2.16.0
>>         limiting behavior.
>>       * Add hardware offload support for matching IPv4/IPv6 frag types
>>         (experimental).
>> +   - Native tunnel:
>> +     * Added new ovs-appctl tnl/neigh/ageing to read/write the neigh ageing
>> +       time.
>> 
>> 
>>  v2.16.0 - 16 Aug 2021
>> diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c
>> index 2769e5c3d..8eacaccd8 100644
>> --- a/lib/tnl-neigh-cache.c
>> +++ b/lib/tnl-neigh-cache.c
>> @@ -47,6 +47,7 @@
>> 
>>  /* In milliseconds */
>>  #define NEIGH_ENTRY_DEFAULT_IDLE_TIME  (15 * 60 * 1000)
>> +#define NEIGH_ENTRY_MAX_AGEING_TIME    (3600 * 1000)
>
> Same remark, using _MS suffix would be nice.
>
>> 
>>  struct tnl_neigh_entry {
>>      struct cmap_node cmap_node;
>> @@ -58,6 +59,7 @@ struct tnl_neigh_entry {
>> 
>>  static struct cmap table = CMAP_INITIALIZER;
>>  static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
>> +static atomic_uint32_t neigh_ageing;
>> 
>>  static uint32_t
>>  tnl_neigh_hash(const struct in6_addr *ip)
>> @@ -75,6 +77,15 @@ tnl_neigh_expired(struct tnl_neigh_entry *neigh)
>>      return expired <= time_msec();
>>  }
>> 
>> +static uint32_t
>> +tnl_neigh_get_ageing(void)
>> +{
>> +    unsigned int ageing;
>> +
>> +    atomic_read_relaxed(&neigh_ageing, &ageing);
>> +    return ageing;
>> +}
>> +
>>  static struct tnl_neigh_entry *
>>  tnl_neigh_lookup__(const char br_name[IFNAMSIZ], const struct in6_addr 
>> *dst)
>>  {
>> @@ -89,7 +100,7 @@ tnl_neigh_lookup__(const char br_name[IFNAMSIZ], 
>> const struct in6_addr *dst)
>>              }
>> 
>>              atomic_store_relaxed(&neigh->expires, time_msec() +
>> -                                 NEIGH_ENTRY_DEFAULT_IDLE_TIME);
>> +                                 tnl_neigh_get_ageing());
>>              return neigh;
>>          }
>>      }
>> @@ -134,7 +145,7 @@ tnl_neigh_set__(const char name[IFNAMSIZ], const 
>> struct in6_addr *dst,
>>      if (neigh) {
>>          if (eth_addr_equals(neigh->mac, mac)) {
>>              atomic_store_relaxed(&neigh->expires, time_msec() +
>> -                                 NEIGH_ENTRY_DEFAULT_IDLE_TIME);
>> +                                 tnl_neigh_get_ageing());
>>              ovs_mutex_unlock(&mutex);
>>              return;
>>          }
>> @@ -147,7 +158,7 @@ tnl_neigh_set__(const char name[IFNAMSIZ], const 
>> struct in6_addr *dst,
>>      neigh->ip = *dst;
>>      neigh->mac = mac;
>>      atomic_store_relaxed(&neigh->expires, time_msec() +
>> -                         NEIGH_ENTRY_DEFAULT_IDLE_TIME);
>> +                         tnl_neigh_get_ageing());
>>      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);
>> @@ -273,6 +284,43 @@ tnl_neigh_cache_flush(struct unixctl_conn *conn, 
>> int argc OVS_UNUSED,
>>      unixctl_command_reply(conn, "OK");
>>  }
>> 
>> +static void
>> +tnl_neigh_cache_ageing(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 ageing;
>> +
>> +    if (argc == 1) {
>> +        struct ds ds = DS_EMPTY_INITIALIZER;
>> +        ds_put_format(&ds, "%"PRIu32, tnl_neigh_get_ageing() / 1000);
>> +        unixctl_command_reply(conn, ds_cstr(&ds));
>> +        ds_destroy(&ds);
>> +
>> +        return;
>> +    }
>> +
>> +    if (!ovs_scan(argv[1], "%"SCNu32, &ageing) ||
>> +        !ageing || ageing > NEIGH_ENTRY_MAX_AGEING_TIME) {
>
> ageing is provided in seconds, while NEIGH_ENTRY_MAX_AGEING_TIME is
> in milliseconds right?
>

that's a leftover of a move around/revert back. It should really be in
seconds as it was.
Thanks for spotting this. While at it I will add a range check in the
test.

>> +        unixctl_command_reply_error(conn, "bad ageing value");
>> +        return;
>> +    }
>> +
>> +    ageing *= 1000;
>> +    atomic_store_relaxed(&neigh_ageing, ageing);
>
> Release here with acquire in tnl_neigh_get_ageing() might be needed.
>

ACK

>> +    new_exp = time_msec() + ageing;
>> +
>> +    CMAP_FOR_EACH (neigh, cmap_node, &table) {
>> +        atomic_read_relaxed(&neigh->expires, &curr_exp);
>> +        if (new_exp < curr_exp) {
>> +            atomic_store_relaxed(&neigh->expires, new_exp);
>> +        }
>
> Potential re-ordering issue between read and write seems more acute here.
> The explicit acquire / release ordering should probably be used.
>

Same remark as in patch 1.
A store after a conditional based on the outcome of the load.
If control dependency is not enough, guess we could use:

atomic_read_explicit(&neigh->expires, &curr_exp, memory_order_acquire)
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)
>>  {
>> @@ -347,10 +395,21 @@ tnl_neigh_cache_show(struct unixctl_conn *conn, 
>> int argc OVS_UNUSED,
>>  void
>>  tnl_neigh_cache_init(void)
>>  {
>> -    unixctl_command_register("tnl/arp/show", "", 0, 0, 
>> tnl_neigh_cache_show, NULL);
>> -    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3, 
>> tnl_neigh_cache_add, NULL);
>> -    unixctl_command_register("tnl/arp/flush", "", 0, 0, 
>> tnl_neigh_cache_flush, NULL);
>> -    unixctl_command_register("tnl/neigh/show", "", 0, 0, 
>> tnl_neigh_cache_show, NULL);
>> -    unixctl_command_register("tnl/neigh/set", "BRIDGE IP MAC", 3, 3, 
>> tnl_neigh_cache_add, NULL);
>> -    unixctl_command_register("tnl/neigh/flush", "", 0, 0, 
>> tnl_neigh_cache_flush, NULL);
>> +    atomic_init(&neigh_ageing, NEIGH_ENTRY_DEFAULT_IDLE_TIME);
>> +    unixctl_command_register("tnl/arp/show", "", 0, 0,
>> +                             tnl_neigh_cache_show, NULL);
>> +    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3,
>> +                             tnl_neigh_cache_add, NULL);
>> +    unixctl_command_register("tnl/arp/flush", "", 0, 0,
>> +                             tnl_neigh_cache_flush, NULL);
>> +    unixctl_command_register("tnl/arp/ageing", "[SECS]", 0, 1,
>> +                             tnl_neigh_cache_ageing, NULL);
>> +    unixctl_command_register("tnl/neigh/show", "", 0, 0,
>> +                             tnl_neigh_cache_show, NULL);
>> +    unixctl_command_register("tnl/neigh/set", "BRIDGE IP MAC", 3, 3,
>> +                             tnl_neigh_cache_add, NULL);
>> +    unixctl_command_register("tnl/neigh/flush", "", 0, 0,
>> +                             tnl_neigh_cache_flush, NULL);
>> +    unixctl_command_register("tnl/neigh/ageing", "[SECS]", 0, 1,
>> +                             tnl_neigh_cache_ageing, NULL);
>>  }
>> diff --git a/ofproto/ofproto-tnl-unixctl.man 
>> b/ofproto/ofproto-tnl-unixctl.man
>> index c70cca539..5c2ad4843 100644
>> --- a/ofproto/ofproto-tnl-unixctl.man
>> +++ b/ofproto/ofproto-tnl-unixctl.man
>> @@ -27,6 +27,15 @@ to \fImac\fR.
>>  .IP "\fBtnl/arp/flush\fR"
>>  Flush ARP table.
>>  .
>> +.IP "\fBtnl/neigh/ageing [\fIseconds\fB]\fR"
>> +.IP "\fBtnl/arp/ageing [\fIseconds\fB]\fR"
>> +Changes the ageing time. The accepted values of \fIseconds\fR are
>> +between 1 and 3600. The new entries will get the value as specified in
>> +\fIseconds\fR. For the existing entries, the ageing time is updated
>> +only if the current expiration is greater than \fIseconds\fR.
>> +.IP
>> +If used without arguments, it prints the current ageing value.
>> +.
>>  .IP "\fBtnl/egress_port_range [num1] [num2]\fR"
>>  Set range for UDP source port used for UDP based Tunnels. For
>>  example VxLAN. If case of zero arguments this command prints
>> diff --git a/tests/tunnel-push-pop-ipv6.at 
>> b/tests/tunnel-push-pop-ipv6.at
>> index 59723e63b..766a4bcf8 100644
>> --- a/tests/tunnel-push-pop-ipv6.at
>> +++ b/tests/tunnel-push-pop-ipv6.at
>> @@ -255,6 +255,36 @@ AT_CHECK([cat p0.pcap.txt | grep 
>> 93aa55aa55000086dd6000000000203aff2001cafe | un
>>  
>> 3333ff000093aa55aa55000086dd6000000000203aff2001cafe000000000000000000000088ff0200000000000000000001ff00009387004d46000000002001cafe0000000000000000000000930101aa55aa550000
>>  ])
>> 
>> +dnl Set the ageing time to 5 seconds
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing 5], [0], [OK
>> +])
>> +
>> +dnl Read the current ageing time
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [5
>> +])
>> +
>> +dnl Add an entry
>> +AT_CHECK([ovs-appctl tnl/neigh/set br0 2001:cafe::92 
>> aa:bb:cc:00:00:01], [0], [OK
>> +])
>> +
>> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
>> +2001:cafe::92                                 aa:bb:cc:00:00:01   br0
>> +])
>> +
>> +ovs-appctl time/warp 5000
>> +
>> +dnl Check the entry has been removed
>> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
>> +])
>> +
>> +dnl Restore the ageing time to 900s (default)
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing 900], [0], [OK
>> +])
>> +
>> +dnl Read the current ageing time
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [900
>> +])
>> +
>>  dnl Check ARP Snoop
>>  AT_CHECK([ovs-appctl netdev-dummy/receive p0 
>> 'in_port(1),eth(src=f8:bc:12:44:34:c8,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:c8)'])
>> 
>> diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
>> index 12fc1ef91..385d14ab3 100644
>> --- a/tests/tunnel-push-pop.at
>> +++ b/tests/tunnel-push-pop.at
>> @@ -270,6 +270,36 @@ AT_CHECK([cat p0.pcap.txt | grep 101025d | uniq], 
>> [0], [dnl
>>  
>> ffffffffffffaa55aa55000008060001080006040001aa55aa550000010102580000000000000101025d
>>  ])
>> 
>> +dnl Set the ageing time to 5 seconds
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing 5], [0], [OK
>> +])
>> +
>> +dnl Read the current ageing time
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [5
>> +])
>> +
>> +dnl Add an entry
>> +AT_CHECK([ovs-appctl tnl/neigh/set br0 1.1.2.92 aa:bb:cc:00:00:01], 
>> [0], [OK
>> +])
>> +
>> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
>> +1.1.2.92                                      aa:bb:cc:00:00:01   br0
>> +])
>> +
>> +ovs-appctl time/warp 5000
>> +
>> +dnl Check the entry has been removed
>> +AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
>> +])
>> +
>> +dnl Restore the ageing time to 900s (default)
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing 900], [0], [OK
>> +])
>> +
>> +dnl Read the current ageing time
>> +AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [900
>> +])
>> +
>>  dnl Check ARP Snoop
>>  AT_CHECK([ovs-appctl netdev-dummy/receive p0 
>> 'recirc_id(0),in_port(1),eth(src=f8:bc:12:44:34:c8,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:c8,tha=00:00:00:00:00:00)'])
>> 
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
> -- 
> Gaetan Rivet
Gaetan Rivet Nov. 9, 2021, 10:54 a.m. UTC | #3
On Mon, Nov 8, 2021, at 20:30, Paolo Valerio wrote:
[...]
>>> +    new_exp = time_msec() + ageing;
>>> +
>>> +    CMAP_FOR_EACH (neigh, cmap_node, &table) {
>>> +        atomic_read_relaxed(&neigh->expires, &curr_exp);
>>> +        if (new_exp < curr_exp) {
>>> +            atomic_store_relaxed(&neigh->expires, new_exp);
>>> +        }
>>
>> Potential re-ordering issue between read and write seems more acute here.
>> The explicit acquire / release ordering should probably be used.
>>
>
> Same remark as in patch 1.
> A store after a conditional based on the outcome of the load.
> If control dependency is not enough, guess we could use:
>
> atomic_read_explicit(&neigh->expires, &curr_exp, memory_order_acquire)
> atomic_store_explicit(&neigh->expires, new_exp, memory_order_release)
>

Control dependency is sufficient for ARM (and x86 implements implicit acq_rel anyway).
So it is probably fine as-is.
diff mbox series

Patch

diff --git a/NEWS b/NEWS
index 90f4b1590..148dd5d61 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,9 @@  Post-v2.16.0
        limiting behavior.
      * Add hardware offload support for matching IPv4/IPv6 frag types
        (experimental).
+   - Native tunnel:
+     * Added new ovs-appctl tnl/neigh/ageing to read/write the neigh ageing
+       time.
 
 
 v2.16.0 - 16 Aug 2021
diff --git a/lib/tnl-neigh-cache.c b/lib/tnl-neigh-cache.c
index 2769e5c3d..8eacaccd8 100644
--- a/lib/tnl-neigh-cache.c
+++ b/lib/tnl-neigh-cache.c
@@ -47,6 +47,7 @@ 
 
 /* In milliseconds */
 #define NEIGH_ENTRY_DEFAULT_IDLE_TIME  (15 * 60 * 1000)
+#define NEIGH_ENTRY_MAX_AGEING_TIME    (3600 * 1000)
 
 struct tnl_neigh_entry {
     struct cmap_node cmap_node;
@@ -58,6 +59,7 @@  struct tnl_neigh_entry {
 
 static struct cmap table = CMAP_INITIALIZER;
 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
+static atomic_uint32_t neigh_ageing;
 
 static uint32_t
 tnl_neigh_hash(const struct in6_addr *ip)
@@ -75,6 +77,15 @@  tnl_neigh_expired(struct tnl_neigh_entry *neigh)
     return expired <= time_msec();
 }
 
+static uint32_t
+tnl_neigh_get_ageing(void)
+{
+    unsigned int ageing;
+
+    atomic_read_relaxed(&neigh_ageing, &ageing);
+    return ageing;
+}
+
 static struct tnl_neigh_entry *
 tnl_neigh_lookup__(const char br_name[IFNAMSIZ], const struct in6_addr *dst)
 {
@@ -89,7 +100,7 @@  tnl_neigh_lookup__(const char br_name[IFNAMSIZ], const struct in6_addr *dst)
             }
 
             atomic_store_relaxed(&neigh->expires, time_msec() +
-                                 NEIGH_ENTRY_DEFAULT_IDLE_TIME);
+                                 tnl_neigh_get_ageing());
             return neigh;
         }
     }
@@ -134,7 +145,7 @@  tnl_neigh_set__(const char name[IFNAMSIZ], const struct in6_addr *dst,
     if (neigh) {
         if (eth_addr_equals(neigh->mac, mac)) {
             atomic_store_relaxed(&neigh->expires, time_msec() +
-                                 NEIGH_ENTRY_DEFAULT_IDLE_TIME);
+                                 tnl_neigh_get_ageing());
             ovs_mutex_unlock(&mutex);
             return;
         }
@@ -147,7 +158,7 @@  tnl_neigh_set__(const char name[IFNAMSIZ], const struct in6_addr *dst,
     neigh->ip = *dst;
     neigh->mac = mac;
     atomic_store_relaxed(&neigh->expires, time_msec() +
-                         NEIGH_ENTRY_DEFAULT_IDLE_TIME);
+                         tnl_neigh_get_ageing());
     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);
@@ -273,6 +284,43 @@  tnl_neigh_cache_flush(struct unixctl_conn *conn, int argc OVS_UNUSED,
     unixctl_command_reply(conn, "OK");
 }
 
+static void
+tnl_neigh_cache_ageing(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 ageing;
+
+    if (argc == 1) {
+        struct ds ds = DS_EMPTY_INITIALIZER;
+        ds_put_format(&ds, "%"PRIu32, tnl_neigh_get_ageing() / 1000);
+        unixctl_command_reply(conn, ds_cstr(&ds));
+        ds_destroy(&ds);
+
+        return;
+    }
+
+    if (!ovs_scan(argv[1], "%"SCNu32, &ageing) ||
+        !ageing || ageing > NEIGH_ENTRY_MAX_AGEING_TIME) {
+        unixctl_command_reply_error(conn, "bad ageing value");
+        return;
+    }
+
+    ageing *= 1000;
+    atomic_store_relaxed(&neigh_ageing, ageing);
+    new_exp = time_msec() + ageing;
+
+    CMAP_FOR_EACH (neigh, cmap_node, &table) {
+        atomic_read_relaxed(&neigh->expires, &curr_exp);
+        if (new_exp < curr_exp) {
+            atomic_store_relaxed(&neigh->expires, new_exp);
+        }
+    }
+
+    unixctl_command_reply(conn, "OK");
+}
+
 static int
 lookup_any(const char *host_name, struct in6_addr *address)
 {
@@ -347,10 +395,21 @@  tnl_neigh_cache_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
 void
 tnl_neigh_cache_init(void)
 {
-    unixctl_command_register("tnl/arp/show", "", 0, 0, tnl_neigh_cache_show, NULL);
-    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3, tnl_neigh_cache_add, NULL);
-    unixctl_command_register("tnl/arp/flush", "", 0, 0, tnl_neigh_cache_flush, NULL);
-    unixctl_command_register("tnl/neigh/show", "", 0, 0, tnl_neigh_cache_show, NULL);
-    unixctl_command_register("tnl/neigh/set", "BRIDGE IP MAC", 3, 3, tnl_neigh_cache_add, NULL);
-    unixctl_command_register("tnl/neigh/flush", "", 0, 0, tnl_neigh_cache_flush, NULL);
+    atomic_init(&neigh_ageing, NEIGH_ENTRY_DEFAULT_IDLE_TIME);
+    unixctl_command_register("tnl/arp/show", "", 0, 0,
+                             tnl_neigh_cache_show, NULL);
+    unixctl_command_register("tnl/arp/set", "BRIDGE IP MAC", 3, 3,
+                             tnl_neigh_cache_add, NULL);
+    unixctl_command_register("tnl/arp/flush", "", 0, 0,
+                             tnl_neigh_cache_flush, NULL);
+    unixctl_command_register("tnl/arp/ageing", "[SECS]", 0, 1,
+                             tnl_neigh_cache_ageing, NULL);
+    unixctl_command_register("tnl/neigh/show", "", 0, 0,
+                             tnl_neigh_cache_show, NULL);
+    unixctl_command_register("tnl/neigh/set", "BRIDGE IP MAC", 3, 3,
+                             tnl_neigh_cache_add, NULL);
+    unixctl_command_register("tnl/neigh/flush", "", 0, 0,
+                             tnl_neigh_cache_flush, NULL);
+    unixctl_command_register("tnl/neigh/ageing", "[SECS]", 0, 1,
+                             tnl_neigh_cache_ageing, NULL);
 }
diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man
index c70cca539..5c2ad4843 100644
--- a/ofproto/ofproto-tnl-unixctl.man
+++ b/ofproto/ofproto-tnl-unixctl.man
@@ -27,6 +27,15 @@  to \fImac\fR.
 .IP "\fBtnl/arp/flush\fR"
 Flush ARP table.
 .
+.IP "\fBtnl/neigh/ageing [\fIseconds\fB]\fR"
+.IP "\fBtnl/arp/ageing [\fIseconds\fB]\fR"
+Changes the ageing time. The accepted values of \fIseconds\fR are
+between 1 and 3600. The new entries will get the value as specified in
+\fIseconds\fR. For the existing entries, the ageing time is updated
+only if the current expiration is greater than \fIseconds\fR.
+.IP
+If used without arguments, it prints the current ageing value.
+.
 .IP "\fBtnl/egress_port_range [num1] [num2]\fR"
 Set range for UDP source port used for UDP based Tunnels. For
 example VxLAN. If case of zero arguments this command prints
diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
index 59723e63b..766a4bcf8 100644
--- a/tests/tunnel-push-pop-ipv6.at
+++ b/tests/tunnel-push-pop-ipv6.at
@@ -255,6 +255,36 @@  AT_CHECK([cat p0.pcap.txt | grep 93aa55aa55000086dd6000000000203aff2001cafe | un
 3333ff000093aa55aa55000086dd6000000000203aff2001cafe000000000000000000000088ff0200000000000000000001ff00009387004d46000000002001cafe0000000000000000000000930101aa55aa550000
 ])
 
+dnl Set the ageing time to 5 seconds
+AT_CHECK([ovs-appctl tnl/neigh/ageing 5], [0], [OK
+])
+
+dnl Read the current ageing time
+AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [5
+])
+
+dnl Add an entry
+AT_CHECK([ovs-appctl tnl/neigh/set br0 2001:cafe::92 aa:bb:cc:00:00:01], [0], [OK
+])
+
+AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
+2001:cafe::92                                 aa:bb:cc:00:00:01   br0
+])
+
+ovs-appctl time/warp 5000
+
+dnl Check the entry has been removed
+AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
+])
+
+dnl Restore the ageing time to 900s (default)
+AT_CHECK([ovs-appctl tnl/neigh/ageing 900], [0], [OK
+])
+
+dnl Read the current ageing time
+AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [900
+])
+
 dnl Check ARP Snoop
 AT_CHECK([ovs-appctl netdev-dummy/receive p0 'in_port(1),eth(src=f8:bc:12:44:34:c8,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=58,tclass=0,hlimit=255,frag=no),icmpv6(type=136,code=0),nd(target=2001:cafe::92,sll=00:00:00:00:00:00,tll=f8:bc:12:44:34:c8)'])
 
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index 12fc1ef91..385d14ab3 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -270,6 +270,36 @@  AT_CHECK([cat p0.pcap.txt | grep 101025d | uniq], [0], [dnl
 ffffffffffffaa55aa55000008060001080006040001aa55aa550000010102580000000000000101025d
 ])
 
+dnl Set the ageing time to 5 seconds
+AT_CHECK([ovs-appctl tnl/neigh/ageing 5], [0], [OK
+])
+
+dnl Read the current ageing time
+AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [5
+])
+
+dnl Add an entry
+AT_CHECK([ovs-appctl tnl/neigh/set br0 1.1.2.92 aa:bb:cc:00:00:01], [0], [OK
+])
+
+AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
+1.1.2.92                                      aa:bb:cc:00:00:01   br0
+])
+
+ovs-appctl time/warp 5000
+
+dnl Check the entry has been removed
+AT_CHECK([ovs-appctl tnl/neigh/show | grep br0 | sort], [0], [dnl
+])
+
+dnl Restore the ageing time to 900s (default)
+AT_CHECK([ovs-appctl tnl/neigh/ageing 900], [0], [OK
+])
+
+dnl Read the current ageing time
+AT_CHECK([ovs-appctl tnl/neigh/ageing], [0], [900
+])
+
 dnl Check ARP Snoop
 AT_CHECK([ovs-appctl netdev-dummy/receive p0 'recirc_id(0),in_port(1),eth(src=f8:bc:12:44:34:c8,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=2,sha=f8:bc:12:44:34:c8,tha=00:00:00:00:00:00)'])